2022-03-15 07:51:34 +00:00
"""
script for telegram bot and its functions
"""
__author__ = " Florian Kellermann, Linus Eickhoff "
2022-05-10 15:37:20 +00:00
__date__ = " 10.05.2022 "
2022-05-11 21:33:48 +00:00
__version__ = " 1.2.3 "
2022-03-15 07:51:34 +00:00
__license__ = " None "
# side-dependencies: none
2022-03-12 16:20:33 +00:00
# Work in Progress
2022-03-12 17:31:10 +00:00
# text bot at t.me/projektaktienbot
# API Documentation https://core.telegram.org/bots/api
# Code examples https://github.com/eternnoir/pyTelegramBotAPI#getting-started
2022-03-15 08:15:12 +00:00
2022-05-11 21:33:48 +00:00
import datetime as dt
import logging
2022-03-12 18:44:58 +00:00
import os
2022-05-11 21:33:48 +00:00
import re
import sys
2022-03-12 18:44:58 +00:00
2022-03-12 17:31:10 +00:00
import telebot
2022-05-11 21:33:48 +00:00
from dotenv import load_dotenv
from telebot import types
2022-03-15 08:15:12 +00:00
2022-05-11 21:33:48 +00:00
import helper_functions as hf
2022-03-15 13:49:36 +00:00
import news . news_fetcher as news
2022-03-16 08:30:33 +00:00
import shares . share_fetcher as share_fetcher
2022-03-29 08:49:02 +00:00
from api_handling . api_handler import API_Handler
2022-03-28 17:39:37 +00:00
2022-09-18 13:24:22 +00:00
2022-05-11 21:33:48 +00:00
load_dotenv ( dotenv_path = ' .env ' ) # load environment variables
2022-03-15 12:53:39 +00:00
2022-05-12 16:09:05 +00:00
bot_version = " 3.0.1 " # version of bot
2022-03-12 17:31:10 +00:00
2022-05-11 21:33:48 +00:00
# create api handler
2022-05-12 16:19:42 +00:00
api_handler = API_Handler ( str ( os . getenv ( " API_URL " ) ) , str ( os . getenv ( " BOT_EMAIL " ) ) , str ( os . getenv ( " BOT_PASSWORD " ) ) ) # get creds from env vars.
2022-04-04 15:33:54 +00:00
print ( " Webserver Token: " + str ( api_handler . token ) )
2022-03-28 17:39:37 +00:00
2022-03-12 18:44:58 +00:00
bot = telebot . TeleBot ( os . getenv ( ' BOT_API_KEY ' ) )
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' start ' , ' Start ' ] )
2022-03-13 09:49:51 +00:00
def send_start ( message ) :
2022-04-30 16:26:10 +00:00
""" Sending welcome message to new user
2022-03-15 14:02:01 +00:00
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /start '
: raises : none
: rtype : none
"""
2022-04-30 16:26:10 +00:00
bot . reply_to ( message , " Welcome to this share bot project. \
\nType / help to get information on what this bot can do . \
2022-09-17 22:39:03 +00:00
\nAlso see " + os.getenv( " APP_URL " ) + " \
2022-04-30 16:26:10 +00:00
to start configuring your bot " )
2022-03-15 12:53:39 +00:00
2022-04-19 19:36:16 +00:00
@bot.message_handler ( commands = [ ' version ' , ' Version ' ] )
2022-03-13 12:35:50 +00:00
def send_version ( message ) :
2022-03-15 14:02:01 +00:00
""" Sending programm version
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /version '
: raises : none
: rtype : none
"""
2022-04-25 17:00:02 +00:00
bot . reply_to ( message , " the current bot version is " + bot_version )
2022-03-12 17:31:10 +00:00
2022-03-15 12:53:39 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' help ' , ' Help ' ] ) # /help -> sending all functions
2022-04-25 17:56:41 +00:00
def send_help ( message ) :
2022-03-15 14:02:01 +00:00
""" Send all functions
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /help '
: raises : none
: rtype : none
"""
2022-05-11 21:33:48 +00:00
bot . reply_to ( message ,
2022-09-17 22:39:03 +00:00
" /id or /auth get your user id \n /shares get update on interesting shares \n /setAdmin set admin rights of user (ADMIN) \n /users see all users. (ADMIN) \n /me get my user info \n /news get top article for each keyword. \n /allnews get all news (last 7 days) \n /keywords get all your keywords \n /addkeyword add a keyword \n /removekeyword remove a keyword \n /transactions get all transactions \n /newtransaction create new transaction \n /share get price of specific share \n /portfolio see own stock portfolio \n /removeshare removes share from portfolio \n /interval get update interval \n /setinterval set update interval \n For further details see " + os . getenv ( " APP_URL " ) )
2022-03-15 12:53:39 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' users ' , ' Users ' ] ) # /users -> sending all users
2022-03-13 10:34:36 +00:00
def send_all_users ( message ) :
2022-03-15 14:02:01 +00:00
""" Send all users, only possible for admins
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /users '
: raises : none
: rtype : none
"""
2022-04-25 17:18:07 +00:00
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
user_data = api_handler . get_user ( user_id )
if ( user_data [ " admin " ] == False ) : # check if user has admin rights
2022-04-25 17:18:07 +00:00
bot . reply_to ( message , " You have to be an admin to use this command " )
return
2022-05-11 21:33:48 +00:00
2022-04-25 17:18:07 +00:00
user_list = api_handler . get_all_users ( )
user_count = len ( user_list )
bot . send_message ( chat_id = user_id , text = " There are " + str ( user_count ) + " users in the database: " )
2022-04-25 17:56:41 +00:00
2022-05-11 21:33:48 +00:00
for user in user_list :
2022-04-25 17:18:07 +00:00
username = user [ ' username ' ]
email = user [ ' email ' ]
2022-04-25 17:56:41 +00:00
id = user [ ' telegram_user_id ' ]
2022-04-25 17:18:07 +00:00
cron = user [ ' cron ' ]
admin = user [ ' admin ' ]
2022-05-11 21:33:48 +00:00
bot . send_message ( chat_id = user_id , text = f ' Username: { username } \n Email: { email } \n ID: { id } \n Cron: { cron } \n Admin: { admin } ' ) # format user data into readable message text
2022-04-25 17:56:41 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' setAdmin ' , ' SetAdmin ' , ' setadmin ' , ' Setadmin ' ] ) # set admin rights to user TBD: not working!!
2022-04-25 17:56:41 +00:00
def set_admin ( message ) :
""" Set admin rights to user
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /setAdmin '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
user_data = api_handler . get_user ( user_id )
2022-04-25 17:56:41 +00:00
2022-05-11 21:33:48 +00:00
if ( user_data [ " admin " ] == False ) : # check if user has admin rights
2022-04-25 17:56:41 +00:00
bot . reply_to ( message , " You have to be an admin to use this command " )
return
2022-05-11 21:33:48 +00:00
bot . send_message ( chat_id = user_id , text = ' send email and true if this account should have admin rights, else false \n in format: <email>,<is_admin> ' ) # request email and admin rights to change to
2022-04-25 17:56:41 +00:00
bot . register_next_step_handler ( message , set_admin_step )
2022-05-11 21:33:48 +00:00
2022-04-25 17:56:41 +00:00
def set_admin_step ( message ) :
str_message = str ( message . text )
2022-05-11 21:33:48 +00:00
args_message = str_message . split ( ' , ' ) # split message into email and admin rights
2022-04-25 17:56:41 +00:00
2022-05-11 21:33:48 +00:00
if len ( args_message ) != 2 : # make sure 2 args (email,is_admin) are given
2022-04-25 17:56:41 +00:00
bot . reply_to ( message , " exactly 2 arguments (<email>,<is_admin>) required, try again " )
return
email = args_message [ 0 ]
2022-05-11 21:33:48 +00:00
is_admin = False # default: False
2022-04-26 10:21:37 +00:00
2022-05-11 21:33:48 +00:00
if args_message [ 1 ] . lower ( ) == " true " : # if user types true, set is_admin to true
2022-04-26 10:21:37 +00:00
is_admin = True
2022-05-11 21:33:48 +00:00
status = api_handler . set_admin ( email , is_admin ) # set admin in db
if ( status == 200 ) :
2022-04-25 17:56:41 +00:00
bot . reply_to ( message , " Admin rights set " )
2022-05-11 21:33:48 +00:00
2022-04-25 17:56:41 +00:00
else :
bot . reply_to ( message , f " Admin rights could not be set ( { status } ) " )
2022-04-17 11:07:57 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' me ' , ' Me ' ] ) # /me -> sending user info
def send_user ( message ) :
""" Send user data
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /me '
: raises : none
2022-04-17 11:07:57 +00:00
2022-05-11 21:33:48 +00:00
: rtype : none
"""
user_id = int ( message . from_user . id )
user_data = api_handler . get_user ( user_id )
if not user_data or user_data == None : # true if user is not registered
2022-09-17 22:39:03 +00:00
bot . reply_to ( message , " This didn \' t work. Make sure to connect your telegram id (/id) on " + os . getenv ( " APP_URL " ) )
2022-05-11 21:33:48 +00:00
return
username = user_data [ ' username ' ]
email = user_data [ ' email ' ]
user_id = user_data [ ' telegram_user_id ' ]
cron = user_data [ ' cron ' ]
admin = user_data [ ' admin ' ]
bot . reply_to ( message , f ' Username: { username } \n Email: { email } \n ID: { user_id } \n Cron: { cron } \n Admin: { admin } ' ) # format user data into readable message text
2022-04-17 11:07:57 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' id ' , ' auth ' , ' Id ' , ' Auth ' ] ) # /auth or /id -> Authentication with user_id over web tool
2022-03-13 08:05:44 +00:00
def send_id ( message ) :
2022-03-15 14:02:01 +00:00
""" Send user id for authentication with browser
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /id ' or ' /auth '
: raises : none
: rtype : none
"""
2022-09-17 22:39:03 +00:00
answer = ' Your ID/Authentication Code is: [ ' + str ( message . from_user . id ) + ' ]. Enter this code in the settings on ' + os . getenv ( " APP_URL " ) + ' to get updates on your shares. '
2022-03-13 08:05:44 +00:00
bot . reply_to ( message , answer )
2022-03-12 17:31:10 +00:00
2022-03-13 09:49:51 +00:00
2022-05-11 21:33:48 +00:00
# function that can be used to ensure that the bot is online and running
2022-04-19 19:36:16 +00:00
@bot.message_handler ( commands = [ ' status ' , ' Status ' ] )
2022-03-29 06:31:58 +00:00
def send_status ( message ) :
""" Sends status to user
: type message : message object bot
: param message : message that was reacted to , if no other command handler gets called
: raises : none
: rtype : none
"""
bot . reply_to ( message , " bot is running " )
2022-05-13 09:59:11 +00:00
@bot.message_handler ( commands = [ ' portfolio ' , ' Portfolio ' ] ) # /portfolio -> print all owned shares
2022-04-20 09:03:21 +00:00
def update_for_user ( message ) :
p_user_id = int ( message . from_user . id )
p_my_handler = api_handler
2022-05-11 21:33:48 +00:00
2022-04-20 09:03:21 +00:00
share_symbols = [ ]
share_amounts = [ ]
2022-05-11 21:33:48 +00:00
2022-04-20 09:03:21 +00:00
my_portfolio = p_my_handler . get_user_portfolio ( p_user_id )
2022-05-11 21:33:48 +00:00
2022-05-12 16:09:05 +00:00
if my_portfolio == None : # true if user is not registered
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = p_user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-05-12 16:09:05 +00:00
return
my_user = p_my_handler . get_user ( p_user_id )
send_to_user ( " Hello %s this is your share update: " % str ( my_user [ " username " ] ) , pUser_id = p_user_id )
2022-04-20 09:03:21 +00:00
for element in my_portfolio :
2022-05-11 21:33:48 +00:00
if element [ " count " ] != ' ' and element [ " isin " ] != ' ' :
2022-04-26 07:36:25 +00:00
print ( element [ " count " ] , element [ " isin " ] )
share_symbols . append ( element [ " isin " ] )
2022-04-20 09:03:21 +00:00
share_amounts . append ( element [ " count " ] )
2022-05-12 16:09:05 +00:00
2022-05-11 21:33:48 +00:00
2022-04-20 09:03:21 +00:00
if len ( share_symbols ) != 0 :
for i in range ( len ( share_symbols ) ) :
2022-05-10 19:51:27 +00:00
my_price = share_fetcher . get_share_price_no_currency ( share_symbols [ i ] )
2022-05-12 13:46:29 +00:00
amounts = hf . make_markdown_proof ( share_amounts [ i ] )
my_update_message = f ' { share_fetcher . get_share_information_markdown ( share_symbols [ i ] ) } \n count: { amounts } \n Total: { hf . make_markdown_proof ( round ( float ( my_price ) * float ( share_amounts [ i ] ) , 2 ) ) } EUR '
2022-05-10 19:51:27 +00:00
bot . send_message ( chat_id = p_user_id , text = my_update_message , parse_mode = " MARKDOWNV2 " )
2022-04-20 09:03:21 +00:00
else :
2022-09-17 22:39:03 +00:00
send_to_user ( " No shares found for your account. Check " + os . getenv ( " APP_URL " ) + " to change your settings and add shares. " , pUser_id = p_user_id )
2022-05-11 21:33:48 +00:00
2022-04-26 07:31:25 +00:00
def send_to_user ( pText , pUser_id ) :
2022-04-20 09:03:21 +00:00
""" Send message to user
: type pText : string
: param pText : Text to send to user
: type pUser_id : int
: param pUser_id : user to send to . per default me ( Florian Kellermann )
2022-03-15 14:02:01 +00:00
: raises : none
: rtype : none
"""
2022-04-20 09:03:21 +00:00
bot . send_message ( chat_id = pUser_id , text = pText )
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' share ' , ' Share ' ] ) # /share -> get share price
2022-03-16 16:42:46 +00:00
def send_share_update ( message ) :
2022-03-16 08:30:33 +00:00
""" Send price of a specific share
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /share '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
2022-05-07 15:50:32 +00:00
bot . send_message ( chat_id = user_id , text = ' Send Symbol/ISIN of share or name of company: ' )
2022-03-16 09:02:28 +00:00
bot . register_next_step_handler ( message , send_share_price )
2022-05-11 21:33:48 +00:00
2022-03-16 09:02:28 +00:00
def send_share_price ( message ) :
2022-05-10 19:51:27 +00:00
str_share_price = share_fetcher . get_share_information_markdown ( str ( message . text ) )
bot . reply_to ( message , str_share_price , parse_mode = " MARKDOWNV2 " )
2022-03-13 09:49:51 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' allnews ' , ' Allnews ' ] ) # /allnews -> get all news
2022-04-04 16:59:00 +00:00
def send_all_news ( message ) :
2022-03-15 14:02:01 +00:00
""" Get news for keywords of user
: type message : message object bot
2022-04-04 16:59:00 +00:00
: param message : message that was reacted to , in this case always containing ' /allnews '
2022-03-15 14:02:01 +00:00
: raises : none
: rtype : none
"""
2022-05-07 15:50:32 +00:00
2022-03-15 12:53:39 +00:00
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
keywords = api_handler . get_user_keywords ( user_id ) # get keywords of user
2022-04-04 16:59:00 +00:00
2022-05-11 21:33:48 +00:00
if keywords == None : # true if user is not registered
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-04-04 16:59:00 +00:00
return
2022-05-11 21:33:48 +00:00
if not keywords : # true if user is registered but does not have any keywords
2022-05-10 16:22:03 +00:00
bot . send_message ( chat_id = user_id , text = ' You have no keywords. Please add some keywords with /addkeyword ' )
2022-04-04 16:59:00 +00:00
return
2022-05-11 21:33:48 +00:00
keywords_search = ' OR ' . join ( keywords ) # concat all keywords with OR -> NewsAPI can understand OR, AND, NOT etc.
now = dt . datetime . now ( ) . date ( ) # get current date
from_date = now - dt . timedelta ( days = 7 ) # get date 7 days ago -> limit age of news to 7 days old max
2022-03-29 11:37:44 +00:00
from_date_formatted = dt . datetime . strftime ( from_date , ' % Y- % m- %d ' )
2022-05-11 21:33:48 +00:00
news_list = news . get_all_news_by_keyword ( keywords_search , from_date_formatted ) [ " articles " ] # array of JSON article objects
2022-03-29 08:49:02 +00:00
2022-05-11 21:33:48 +00:00
if news_list : # true if news_list is not empty
2022-03-29 10:20:58 +00:00
for article in news_list :
formatted_article = news . format_article ( article )
2022-05-11 21:33:48 +00:00
bot . send_message ( chat_id = user_id , text = formatted_article , parse_mode = " MARKDOWNV2 " ) # Markdown allows to write bold text with * etc.
2022-03-29 10:20:58 +00:00
else :
bot . send_message ( chat_id = user_id , text = ' No news found for your keywords. ' )
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' news ' , ' News ' ] ) # /news -> get news for specific keyword
2022-04-04 16:59:00 +00:00
def send_news ( message ) :
""" Get news for keywords of user
: type message : message object bot
: param message : message that was reacted to , in this case always containing ' /news '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
keywords = api_handler . get_user_keywords ( user_id ) # get keywords of user
2022-04-04 16:59:00 +00:00
2022-05-11 21:33:48 +00:00
if keywords == None : # true if user is not registered
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-04-04 16:59:00 +00:00
return
2022-05-11 21:33:48 +00:00
if not keywords : # true if user is registered but does not have any keywords
2022-04-04 16:59:00 +00:00
bot . send_message ( chat_id = user_id , text = ' You have no keywords. Please add some keywords with /addkeyword ' )
return
if keywords :
for keyword in keywords :
top_news = news . get_top_news_by_keyword ( keyword ) [ " articles " ]
2022-05-11 21:33:48 +00:00
if top_news == None : # true if request to NewsAPI failed
2022-04-04 16:59:00 +00:00
bot . send_message ( chat_id = user_id , text = ' News Server did not respond correctly. Try again later. ' )
2022-04-25 16:56:19 +00:00
2022-05-11 21:33:48 +00:00
if not top_news : # true if no news found for keyword (empty list)
2022-05-10 16:22:03 +00:00
keyword = hf . make_markdown_proof ( keyword )
bot . send_message ( chat_id = user_id , text = f ' No news found for keyword: * { keyword } * ' , parse_mode = " MARKDOWNV2 " )
2022-04-25 16:59:06 +00:00
2022-04-25 16:56:19 +00:00
else :
2022-05-10 16:22:03 +00:00
keyword = hf . make_markdown_proof ( keyword )
2022-05-11 21:33:48 +00:00
formatted_article = news . format_article ( top_news [ 0 ] ) # only format and send most popular news
bot . send_message ( chat_id = user_id , text = f " _keyword: { keyword } _ \n \n " + formatted_article , parse_mode = " MARKDOWNV2 " ) # do not use v2 because of bugs related t "." in links
2022-03-15 12:53:39 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' addkeyword ' , ' Addkeyword ' ] ) # /addkeyword -> add keyword to user
2022-03-28 17:39:37 +00:00
def add_keyword ( message ) :
""" Add keyword to user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /addkeyword '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
bot . send_message ( chat_id = user_id , text = ' Type keyword to add: ' )
2022-05-11 21:33:48 +00:00
bot . register_next_step_handler ( message , store_keyword ) # wait for user to send keyword, then call store_keyword function
2022-03-28 17:39:37 +00:00
def store_keyword ( message ) :
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
keyword = str ( message . text ) . lower ( ) # lower to ensure Bitcoin and bitcoin is not stored as individual keywords
status = api_handler . set_keyword ( user_id , keyword ) # set keyword in database
if status == 200 : # statuscode 200 means keyword was added successfully without errors
bot . send_message ( chat_id = user_id , text = f ' Keyword " { keyword } " added. ' ) # duplicate keywords are denied by Database, so no need to check for that here
2022-04-04 16:59:00 +00:00
else :
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = f ' Keyword " { keyword } " could not be stored. Make sure to connect your telegram id (/id) on { os . getenv ( " APP_URL " ) } (statuscode { status } ) ' )
2022-03-29 08:49:02 +00:00
2022-03-29 10:04:49 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' removekeyword ' , ' Removekeyword ' ] ) # /removekeyword -> remove keyword from user
2022-03-29 08:49:02 +00:00
def remove_keyword ( message ) :
""" Remove keyword from user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /removekeyword '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
bot . send_message ( chat_id = user_id , text = ' Type keyword to remove: ' )
2022-05-11 21:33:48 +00:00
bot . register_next_step_handler ( message , remove_keyword_step ) # wait for user to send keyword to remove, then call remove_keyword_step function
2022-03-29 08:49:02 +00:00
def remove_keyword_step ( message ) :
user_id = int ( message . from_user . id )
keyword = str ( message . text ) . lower ( )
2022-04-04 16:59:00 +00:00
status = api_handler . delete_keyword ( user_id , keyword )
2022-05-11 21:33:48 +00:00
if status == 200 : # statuscode 200 means keyword was removed successfully without errors
bot . send_message ( chat_id = user_id , text = f ' Keyword " { keyword } " removed. ' ) # checking if keyword to remove is in database are handled in database, not here
2022-04-04 16:59:00 +00:00
else :
bot . send_message ( chat_id = user_id , text = f ' Failed deleting keyword " { keyword } " . (statuscode { status } ) ' )
2022-03-28 17:39:37 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' keywords ' , ' Keywords ' ] ) # /keywords -> get keywords of user
2022-03-29 10:04:49 +00:00
def send_keywords ( message ) :
""" Send keywords of user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /keywords '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
keywords = api_handler . get_user_keywords ( user_id ) # get keywords of user
2022-05-10 16:22:03 +00:00
2022-05-11 21:33:48 +00:00
if keywords == None : # true if user is not registered
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-04-04 16:59:00 +00:00
return
2022-05-10 16:22:03 +00:00
2022-05-11 21:33:48 +00:00
if not keywords : # true if user is registered but does not have any keywords
2022-04-04 16:59:00 +00:00
bot . send_message ( chat_id = user_id , text = ' No keywords set for this account. Add keywords by using /addkeyword ' )
return
2022-05-10 16:22:03 +00:00
2022-05-11 21:33:48 +00:00
else : # send keyword list
2022-04-04 16:59:00 +00:00
keywords_str = ' , ' . join ( keywords )
2022-05-10 16:22:03 +00:00
keywords_str = hf . make_markdown_proof ( keywords_str )
2022-05-11 21:33:48 +00:00
2022-05-10 16:22:03 +00:00
text = f ' Your keywords are: _ { keywords_str } _ '
bot . send_message ( chat_id = user_id , text = text , parse_mode = " MARKDOWNV2 " )
2022-03-29 10:04:49 +00:00
2022-05-10 06:57:56 +00:00
@bot.message_handler ( commands = [ ' removeshare ' , ' Removeshare ' ] )
def remove_share ( message ) :
""" Remove share from portfolio
: type message : message object bot
: param message : message that was reacted to , in this case always ' /removeshare '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-12 07:39:57 +00:00
bot . send_message ( chat_id = user_id , text = ' Type ISIN/Symbol/CompanyName of share to remove (if you are unsure do /shares, find your share and insert the value above amount): ' )
2022-05-11 21:33:48 +00:00
bot . register_next_step_handler ( message , remove_share_step ) # wait for user to send ISIN, then call remove_share_step function
2022-05-10 06:57:56 +00:00
def remove_share_step ( message ) :
user_id = int ( message . from_user . id )
isin = str ( message . text )
2022-05-11 21:33:48 +00:00
status = api_handler . delete_share ( int ( user_id ) , str ( isin ) ) # remove share from portfolio
if status == 200 : # statuscode 200 means share was removed successfully without errors
bot . send_message ( chat_id = user_id , text = f ' Share " { isin } " removed. ' ) # checking if share to remove is in database are handled in database, not here
2022-05-10 06:57:56 +00:00
else :
bot . send_message ( chat_id = user_id , text = f ' Failed deleting share " { isin } " . (statuscode { status } ) \n Make sure that the share is in your portfolio and written exactly like there. ' )
2022-05-11 21:33:48 +00:00
@bot.message_handler ( commands = [ ' newtransaction ' , ' Newtransaction ' ] ) # tbd not working rn may be deleted in future
2022-04-17 09:57:28 +00:00
def set_new_transaction ( message ) :
""" Set new transaction for user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /newtransaction '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
bot . send_message ( chat_id = user_id ,
text = ' Type " <name of stock>,<isin/name/symbol>,<amount>,<price_per_stock_usd> " (time of transaction will be set to now, negative amount is selling, positive is buying): ' )
2022-04-17 09:57:28 +00:00
bot . register_next_step_handler ( message , set_new_transaction_step )
2022-05-10 06:57:56 +00:00
2022-04-17 09:57:28 +00:00
def set_new_transaction_step ( message ) :
user_id = int ( message . from_user . id )
2022-05-10 06:57:56 +00:00
if not re . match ( r " [A-Za-z0-9 ]+,[A-Za-z0-9]+,(-)?[0-9]+(.[0-9]+)?,[0-9]+(.[0-9]+)? " , message . text ) :
2022-04-19 19:36:16 +00:00
bot . send_message ( chat_id = user_id , text = ' Invalid format \n (e.g. Apple,US0378331005,53.2,120.4). \n Try again with /newtransaction. ' )
2022-04-17 09:57:28 +00:00
return
2022-05-11 21:33:48 +00:00
2022-04-17 09:57:28 +00:00
transaction_data = str ( message . text ) . split ( ' , ' )
2022-04-19 19:36:16 +00:00
desc = str ( transaction_data [ 0 ] )
isin = str ( transaction_data [ 1 ] )
amount = float ( transaction_data [ 2 ] )
price = float ( transaction_data [ 3 ] )
time = dt . datetime . now ( ) . isoformat ( )
2022-04-26 10:36:01 +00:00
print ( " \n \n \n \n \n " )
print ( f " { isin } , { amount } , { price } , { time } " )
2022-04-19 19:36:16 +00:00
status = api_handler . set_transaction ( user_id , desc , isin , amount , price , time )
2022-04-17 09:57:28 +00:00
if status == 200 :
bot . send_message ( chat_id = user_id , text = ' Transaction succesfully added. ' )
else :
bot . send_message ( chat_id = user_id , text = f ' Failed adding transaction. (statuscode { status } ) ' )
2022-05-11 21:33:48 +00:00
2022-04-25 16:25:22 +00:00
@bot.message_handler ( commands = [ ' interval ' , ' Interval ' ] )
2022-04-17 10:20:53 +00:00
def send_interval ( message ) :
""" send interval for user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /interval '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
user_data = api_handler . get_user ( user_id ) # get cron interval of user (stored in user data)
if user_data == None : # true if user is not registered in DB
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) + ' and set an interval with /setinterval ' )
2022-04-17 10:20:53 +00:00
return
2022-05-11 21:33:48 +00:00
else : # send interval
interval = str ( user_data [ ' cron ' ] ) # get cron from user data
if interval == ' None ' : # true if user has no cron set
2022-04-17 11:07:57 +00:00
bot . send_message ( chat_id = user_id , text = ' You do not have an interval set. Set one with /setinterval ' )
return
2022-05-11 21:33:48 +00:00
formatted_interval = str ( interval ) . replace ( ' ' , ' _ ' ) # replace spaces with underscores to add to url of crontab.guru
2022-04-17 11:07:57 +00:00
bot . send_message ( chat_id = user_id , text = f ' Your update interval: { interval } (https://crontab.guru/# { formatted_interval } ) ' )
2022-05-10 07:49:31 +00:00
@bot.message_handler ( commands = [ ' transactions ' , ' Transactions ' ] )
def send_transactions ( message ) :
""" send transactions for user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /transactions '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
transactions = api_handler . get_user_transactions ( user_id ) # get transactions of user
2022-05-10 07:49:31 +00:00
2022-05-11 21:33:48 +00:00
if transactions == None : # true if user does not exist
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-05-10 07:49:31 +00:00
return
2022-05-11 21:33:48 +00:00
if not transactions : # true if user has no transactions
2022-05-10 07:49:31 +00:00
bot . send_message ( chat_id = user_id , text = ' You do not have any transactions. ' )
return
2022-05-11 21:33:48 +00:00
2022-05-10 07:49:31 +00:00
else :
2022-05-10 16:22:03 +00:00
2022-05-10 07:49:31 +00:00
for transaction in transactions :
2022-05-11 21:33:48 +00:00
comment = hf . make_markdown_proof ( transaction [ ' comment ' ] ) or " \ (no desc \ ) " # if comment is empty, make it "no desc"
2022-05-10 16:22:03 +00:00
isin = hf . make_markdown_proof ( transaction [ ' isin ' ] )
2022-05-10 17:16:44 +00:00
amount = hf . make_markdown_proof ( transaction [ ' count ' ] )
price = hf . make_markdown_proof ( transaction [ ' price ' ] )
time = hf . make_markdown_proof ( transaction [ ' time ' ] )
2022-05-11 21:33:48 +00:00
2022-05-10 17:16:44 +00:00
bot . send_message ( chat_id = user_id , text = f ' _ { comment } _ \n { isin } \n amount: { amount } \n price: { price } \n time: { time } ' , parse_mode = " MARKDOWNV2 " )
2022-05-10 07:49:31 +00:00
@bot.message_handler ( commands = [ ' shares ' , ' Shares ' ] )
def send_shares ( message ) :
""" send shares for user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /shares '
: raises : none
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-05-11 21:33:48 +00:00
shares = api_handler . get_user_shares ( user_id ) # get shares of user
2022-05-10 07:49:31 +00:00
2022-05-11 21:33:48 +00:00
if shares == None : # true if user does not exist
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' This didn \' t work. Make sure to connect your telegram id (/id) on ' + os . getenv ( " APP_URL " ) )
2022-05-11 21:33:48 +00:00
elif not shares : # true if user has no shares
2022-09-17 22:39:03 +00:00
bot . send_message ( chat_id = user_id , text = ' You do not have any shares. Add shares on ' + os . getenv ( " APP_URL " ) )
2022-05-10 14:43:17 +00:00
else :
for element in shares :
2022-05-10 19:51:27 +00:00
bot . send_message ( chat_id = user_id , text = share_fetcher . get_share_information_markdown ( element ) , parse_mode = " MARKDOWNV2 " )
2022-05-10 07:49:31 +00:00
2022-04-25 16:25:22 +00:00
@bot.message_handler ( commands = [ ' setinterval ' , ' Setinterval ' ] )
2022-04-17 10:20:53 +00:00
def set_new_interval ( message ) :
""" Set new interval for user
: type message : message object bot
: param message : message that was reacted to , in this case always ' /setinterval '
: raises : none
2022-04-17 09:57:28 +00:00
2022-04-17 10:20:53 +00:00
: rtype : none
"""
user_id = int ( message . from_user . id )
2022-04-17 10:35:59 +00:00
bot . send_message ( chat_id = user_id , text = ' Type interval in cron format: \n (https://crontab.guru/) ' )
2022-05-11 21:33:48 +00:00
bot . register_next_step_handler ( message , set_new_interval_step ) # executes function when user sends message
2022-04-17 10:20:53 +00:00
2022-05-11 21:33:48 +00:00
def set_new_interval_step ( message ) :
2022-04-17 10:20:53 +00:00
user_id = int ( message . from_user . id )
interval = str ( message . text )
2022-05-11 21:33:48 +00:00
status = api_handler . set_cron_interval ( user_id , interval ) # send cron to db
2022-04-17 10:20:53 +00:00
if status == 200 :
bot . send_message ( chat_id = user_id , text = ' Interval succesfully set. ' )
return
2022-05-11 21:33:48 +00:00
if status == - 1 : # only -1 when interval is invalid, not a real statuscode, but used from api_handler.set_cron_interval to tell the crontab has the wrong format
2022-04-17 11:07:57 +00:00
bot . send_message ( chat_id = user_id , text = ' Invalid interval format. Try again with \n /setinterval. ' )
2022-04-17 10:20:53 +00:00
return
else :
bot . send_message ( chat_id = user_id , text = f ' Failed setting interval. (statuscode { status } ) ' )
2022-04-17 09:57:28 +00:00
2022-05-11 21:33:48 +00:00
@bot.message_handler ( func = lambda message : True ) # Returning that command is unknown for any other statement
2022-03-12 17:31:10 +00:00
def echo_all ( message ) :
2022-03-15 14:02:01 +00:00
""" Tell that command is not known if it is no known command
: type message : message object bot
: param message : message that was reacted to , if no other command handler gets called
: raises : none
: rtype : none
"""
2022-05-11 21:33:48 +00:00
answer = ' Do not know this command or text: ' + message . text
2022-03-12 18:44:58 +00:00
bot . reply_to ( message , answer )
2022-03-13 10:34:36 +00:00
2022-03-12 18:24:25 +00:00
telebot . logger . setLevel ( logging . DEBUG )
2022-03-13 09:49:51 +00:00
2022-05-11 21:33:48 +00:00
@bot.inline_handler ( lambda query : query . query == ' text ' ) # inline prints for debugging
2022-03-12 18:24:25 +00:00
def query_text ( inline_query ) :
2022-03-15 14:02:01 +00:00
""" Output in the console about current user actions and status of bot
: type inline_query :
: param inline_query :
: raises : none
: rtype : none
"""
2022-03-12 18:24:25 +00:00
try :
r = types . InlineQueryResultArticle ( ' 1 ' , ' Result1 ' , types . InputTextMessageContent ( ' hi ' ) )
r2 = types . InlineQueryResultArticle ( ' 2 ' , ' Result2 ' , types . InputTextMessageContent ( ' hi ' ) )
bot . answer_inline_query ( inline_query . id , [ r , r2 ] )
except Exception as e :
print ( e )
2022-03-12 18:44:58 +00:00
2022-03-12 18:24:25 +00:00
def main_loop ( ) :
2022-04-05 12:00:33 +00:00
""" Start bot
2022-03-15 14:02:01 +00:00
: raises : none
: rtype : none
"""
2022-03-12 18:24:25 +00:00
bot . infinity_polling ( )
2022-03-12 17:31:10 +00:00
2022-05-11 21:33:48 +00:00
2023-03-28 09:58:14 +00:00
2022-03-12 18:24:25 +00:00
if __name__ == ' __main__ ' :
try :
main_loop ( )
except KeyboardInterrupt :
print ( ' \n Exiting by user request. \n ' )
2022-05-11 21:33:48 +00:00
sys . exit ( 0 )