<stylemedia="screen and (min-width: 700px)">@mediascreenand(min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em4em;border-left:1pxsolid#ddd}precode{font-size:1em}.item.name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toculul,#indexul{padding-left:1.5em}.toc>ul>li{margin-top:.5em}}</style>
:param message: message that was reacted to, in this case always containing '/version'
:raises: none
:rtype:none
"""
bot.reply_to(message, "the current bot version is " + bot_version)
@bot.message_handler(commands=['help', 'Help']) # /help -> sending all functions
def send_help(message):
""" 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
"""
bot.reply_to(message,
"/id or /auth get your user id\n/update get updates on your shares.\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 portfolio\n/removeshare removes share from portfolio\n/interval get update interval\n/setinterval set update interval\n For further details see https://gruppe1.testsites.info")
@bot.message_handler(commands=['users', 'Users']) # /users -> sending all users
def send_all_users(message):
""" 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
"""
user_id = int(message.from_user.id)
user_data = api_handler.get_user(user_id)
if (user_data["admin"] == False): # check if user has admin rights
bot.reply_to(message, "You have to be an admin to use this command")
return
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:")
for user in user_list:
username = user['username']
email = user['email']
id = user['telegram_user_id']
cron = user['cron']
admin = user['admin']
bot.send_message(chat_id=user_id, text=f'Username: {username}\nEmail: {email}\nID: {id}\nCron: {cron}\nAdmin: {admin}') # format user data into readable message text
@bot.message_handler(commands=['setAdmin', 'SetAdmin', 'setadmin', 'Setadmin']) # set admin rights to user TBD: not working!!
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)
user_data = api_handler.get_user(user_id)
if (user_data["admin"] == False): # check if user has admin rights
bot.reply_to(message, "You have to be an admin to use this command")
return
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
if args_message[1].lower() == "true": # if user types true, set is_admin to true
is_admin = True
status = api_handler.set_admin(email, is_admin) # set admin in db
if (status == 200):
bot.reply_to(message, "Admin rights set")
else:
bot.reply_to(message, f"Admin rights could not be set ({status})")
@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
: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
bot.reply_to(message, "This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info")
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}\nEmail: {email}\nID: {user_id}\nCron: {cron}\nAdmin: {admin}') # format user data into readable message text
@bot.message_handler(commands=['id', 'auth', 'Id', 'Auth']) # /auth or /id -> Authentication with user_id over web tool
def send_id(message):
""" 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
"""
answer = 'Your ID/Authentication Code is: [' + str(message.from_user.id) + ']. Enter this code in the settings on https://gruppe1.testsites.info to get updates on your shares.'
bot.reply_to(message, answer)
# function that can be used to ensure that the bot is online and running
send_to_user("No shares found for your account. Check https://gruppe1.testsites.info to change your settings and add shares.", pUser_id=p_user_id)
def send_to_user(pText, pUser_id):
""" 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)
:raises: none
:rtype: none
"""
bot.send_message(chat_id=pUser_id, text=pText)
@bot.message_handler(commands=['share', 'Share']) # /share -> get share price
def send_share_update(message):
""" 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)
bot.send_message(chat_id=user_id, text='Send Symbol/ISIN of share or name of company:')
if top_news == None: # true if request to NewsAPI failed
bot.send_message(chat_id=user_id, text='News Server did not respond correctly. Try again later.')
if not top_news: # true if no news found for keyword (empty list)
keyword = hf.make_markdown_proof(keyword)
bot.send_message(chat_id=user_id, text=f'No news found for keyword: *{keyword}*', parse_mode="MARKDOWNV2")
else:
keyword = hf.make_markdown_proof(keyword)
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
@bot.message_handler(commands=['addkeyword', 'Addkeyword']) # /addkeyword -> add keyword to user
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:')
bot.register_next_step_handler(message, store_keyword) # wait for user to send keyword, then call store_keyword function
def store_keyword(message):
user_id = int(message.from_user.id)
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
else:
bot.send_message(chat_id=user_id, text=f'Keyword "{keyword}" could not be stored. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info (statuscode {status})')
@bot.message_handler(commands=['removekeyword', 'Removekeyword']) # /removekeyword -> remove keyword from user
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:')
bot.register_next_step_handler(message, remove_keyword_step) # wait for user to send keyword to remove, then call remove_keyword_step function
def remove_keyword_step(message):
user_id = int(message.from_user.id)
keyword = str(message.text).lower()
status = api_handler.delete_keyword(user_id, keyword)
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
:param message: message that was reacted to, in this case always '/portfolio'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
portfolio = api_handler.get_user_portfolio(user_id) # get portfolio of user as json
if portfolio == None: # true if user is not registered
bot.send_message(chat_id=user_id, text='This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info')
return
if not portfolio: # true if user is registered but does not have any stocks in portfolio
bot.send_message(chat_id=user_id, text='You do not have any stocks in your portfolio.')
return
else: # send portfolio
for stock in portfolio:
comment = hf.make_markdown_proof(str(stock["comment"])) # comment may be written name of stock, comment is made by user when adding an stock to portfolio
count = hf.make_markdown_proof("{:.2f}".format(float(stock["count"]))) # round count to 2 decimal places
:param message: message that was reacted to, in this case always '/removeshare'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
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):')
bot.register_next_step_handler(message, remove_share_step) # wait for user to send ISIN, then call remove_share_step function
def remove_share_step(message):
user_id = int(message.from_user.id)
isin = str(message.text)
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
else:
bot.send_message(chat_id=user_id, text=f'Failed deleting share "{isin}". (statuscode {status})\nMake sure that the share is in your portfolio and written exactly like there.')
@bot.message_handler(commands=['newtransaction', 'Newtransaction']) # tbd not working rn may be deleted in future
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)
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):')
:param message: message that was reacted to, in this case always '/interval'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
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
bot.send_message(chat_id=user_id, text='This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info and set an interval with /setinterval')
return
else: # send interval
interval = str(user_data['cron']) # get cron from user data
if interval == 'None': # true if user has no cron set
bot.send_message(chat_id=user_id, text='You do not have an interval set. Set one with /setinterval')
return
formatted_interval = str(interval).replace('', '_') # replace spaces with underscores to add to url of crontab.guru
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
bot.send_message(chat_id=user_id, text='Invalid interval format. Try again with\n /setinterval.')
:param message: message that was reacted to, in this case always '/removekeyword'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['removekeyword', 'Removekeyword']) # /removekeyword -> remove keyword from user
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:')
bot.register_next_step_handler(message, remove_keyword_step) # wait for user to send keyword to remove, then call remove_keyword_step function</code></pre>
status = api_handler.delete_keyword(user_id, keyword)
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
:param message: message that was reacted to, in this case always '/removeshare'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
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):')
bot.register_next_step_handler(message, remove_share_step) # wait for user to send ISIN, then call remove_share_step function</code></pre>
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
else:
bot.send_message(chat_id=user_id, text=f'Failed deleting share "{isin}". (statuscode {status})\nMake sure that the share is in your portfolio and written exactly like there.')</code></pre>
<divclass="desc"><p>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'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['users', 'Users']) # /users -> sending all users
def send_all_users(message):
""" 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
"""
user_id = int(message.from_user.id)
user_data = api_handler.get_user(user_id)
if (user_data["admin"] == False): # check if user has admin rights
bot.reply_to(message, "You have to be an admin to use this command")
return
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:")
for user in user_list:
username = user['username']
email = user['email']
id = user['telegram_user_id']
cron = user['cron']
admin = user['admin']
bot.send_message(chat_id=user_id, text=f'Username: {username}\nEmail: {email}\nID: {id}\nCron: {cron}\nAdmin: {admin}') # format user data into readable message text</code></pre>
:param message: message that was reacted to, in this case always containing '/help'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['help', 'Help']) # /help -> sending all functions
def send_help(message):
""" 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
"""
bot.reply_to(message,
"/id or /auth get your user id\n/update get updates on your shares.\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 portfolio\n/removeshare removes share from portfolio\n/interval get update interval\n/setinterval set update interval\n For further details see https://gruppe1.testsites.info")</code></pre>
<divclass="desc"><p>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'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['id', 'auth', 'Id', 'Auth']) # /auth or /id -> Authentication with user_id over web tool
def send_id(message):
""" 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
"""
answer = 'Your ID/Authentication Code is: [' + str(message.from_user.id) + ']. Enter this code in the settings on https://gruppe1.testsites.info to get updates on your shares.'
:param message: message that was reacted to, in this case always '/interval'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
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
bot.send_message(chat_id=user_id, text='This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info and set an interval with /setinterval')
return
else: # send interval
interval = str(user_data['cron']) # get cron from user data
if interval == 'None': # true if user has no cron set
bot.send_message(chat_id=user_id, text='You do not have an interval set. Set one with /setinterval')
return
formatted_interval = str(interval).replace('', '_') # replace spaces with underscores to add to url of crontab.guru
if top_news == None: # true if request to NewsAPI failed
bot.send_message(chat_id=user_id, text='News Server did not respond correctly. Try again later.')
if not top_news: # true if no news found for keyword (empty list)
keyword = hf.make_markdown_proof(keyword)
bot.send_message(chat_id=user_id, text=f'No news found for keyword: *{keyword}*', parse_mode="MARKDOWNV2")
else:
keyword = hf.make_markdown_proof(keyword)
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</code></pre>
:param message: message that was reacted to, in this case always '/portfolio'
:raises: none
:rtype: none
"""
user_id = int(message.from_user.id)
portfolio = api_handler.get_user_portfolio(user_id) # get portfolio of user as json
if portfolio == None: # true if user is not registered
bot.send_message(chat_id=user_id, text='This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info')
return
if not portfolio: # true if user is registered but does not have any stocks in portfolio
bot.send_message(chat_id=user_id, text='You do not have any stocks in your portfolio.')
return
else: # send portfolio
for stock in portfolio:
comment = hf.make_markdown_proof(str(stock["comment"])) # comment may be written name of stock, comment is made by user when adding an stock to portfolio
count = hf.make_markdown_proof("{:.2f}".format(float(stock["count"]))) # round count to 2 decimal places
:param message: message that was reacted to, in this case always containing '/me'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@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
: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
bot.reply_to(message, "This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info")
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}\nEmail: {email}\nID: {user_id}\nCron: {cron}\nAdmin: {admin}') # format user data into readable message text</code></pre>
:param message: message that was reacted to, in this case always containing '/setAdmin'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['setAdmin', 'SetAdmin', 'setadmin', 'Setadmin']) # set admin rights to user TBD: not working!!
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)
user_data = api_handler.get_user(user_id)
if (user_data["admin"] == False): # check if user has admin rights
bot.reply_to(message, "You have to be an admin to use this command")
return
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
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
bot.send_message(chat_id=user_id, text='Invalid interval format. Try again with\n /setinterval.')
:param message: message that was reacted to, in this case always '/newtransaction'</p>
<p>:raises: none</p>
<p>:rtype: none</p></div>
<detailsclass="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><codeclass="python">@bot.message_handler(commands=['newtransaction', 'Newtransaction']) # tbd not working rn may be deleted in future
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)
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):')
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
else:
bot.send_message(chat_id=user_id, text=f'Keyword "{keyword}" could not be stored. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info (statuscode {status})')</code></pre>
send_to_user("No shares found for your account. Check https://gruppe1.testsites.info to change your settings and add shares.", pUser_id=p_user_id)</code></pre>