commit
68f5806444
@ -1,7 +1,7 @@
|
|||||||
# Dokumentation
|
# Dokumentation
|
||||||
|
|
||||||
## Swagger Documentation
|
## Swagger Documentation
|
||||||
Visit https://aktienbot.flokaiser.com/api/docs
|
Visit https://gruppe1.testsites.info/api/docs
|
||||||
|
|
||||||
## API
|
## API
|
||||||
- `api/openapi.json`
|
- `api/openapi.json`
|
||||||
|
@ -6,3 +6,7 @@ NEWS_API_KEY=
|
|||||||
|
|
||||||
# Flask secret key
|
# Flask secret key
|
||||||
SECRET_KEY=
|
SECRET_KEY=
|
||||||
|
|
||||||
|
# bot credentials
|
||||||
|
BOT_EMAIL=
|
||||||
|
BOT_PASSWORD=
|
@ -1,7 +0,0 @@
|
|||||||
"""
|
|
||||||
script for communicating with webservice to get data from database
|
|
||||||
"""
|
|
||||||
__author__ = "Florian Kellermann, Linus Eickhoff"
|
|
||||||
__date__ = "16.03.2022"
|
|
||||||
__version__ = "0.0.1"
|
|
||||||
__license__ = "None"
|
|
0
telegram_bot/api_handling/__init__.py
Normal file
0
telegram_bot/api_handling/__init__.py
Normal file
350
telegram_bot/api_handling/api_handler.py
Normal file
350
telegram_bot/api_handling/api_handler.py
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
"""
|
||||||
|
script for communicating with webservice to get data from database
|
||||||
|
"""
|
||||||
|
__author__ = "Florian Kellermann, Linus Eickhoff"
|
||||||
|
__date__ = "16.03.2022"
|
||||||
|
__version__ = "0.0.1"
|
||||||
|
__license__ = "None"
|
||||||
|
|
||||||
|
#side-dependencies: none
|
||||||
|
#Work in Progress
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
import requests as r
|
||||||
|
from croniter import croniter
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class API_Handler:
|
||||||
|
"""class for interacting with the api webservice
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
db_adress (string): adress of the database
|
||||||
|
token (string): auth token for api
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
reauthorize(email, password): set new credentials
|
||||||
|
get_user_keywords(user_id): gets the keywords of the user
|
||||||
|
set_keyword(user_id, keyword): sets the keyword of the user
|
||||||
|
delete_keyword(user_id, keyword): deletes the keyword of the user
|
||||||
|
get_user_shares(user_id): gets the shares of the user
|
||||||
|
set_share(user_id, symbol): sets the share of the user
|
||||||
|
delete_share(user_id, symbol): deletes the share of the user
|
||||||
|
get_user_transactions(user_id): gets the transactions of the user
|
||||||
|
set_transaction(user_id, transaction): sets the transaction of the user
|
||||||
|
get_user_portfolio(user_id): gets the portfolio of the user
|
||||||
|
set_portfolio(user_id, portfolio): sets the portfolio of the user
|
||||||
|
delete_portfolio(user_id, portfolio): deletes the portfolio of the user
|
||||||
|
set_cron_interval(user_id, interval): sets the cron interval of the user
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, db_adress, email, password):
|
||||||
|
"""initializes the API_Handler class
|
||||||
|
|
||||||
|
Args:
|
||||||
|
db_adress (string): adress of the database
|
||||||
|
email (string): email of the user
|
||||||
|
password (string): password of the user
|
||||||
|
"""
|
||||||
|
self.db_adress = db_adress
|
||||||
|
|
||||||
|
payload = {'email': email, 'password': password}
|
||||||
|
with r.Session() as s:
|
||||||
|
p = s.post(self.db_adress + "/user/login", json=payload)
|
||||||
|
if p.status_code == 200:
|
||||||
|
self.token = p.json()["data"]['token']
|
||||||
|
else:
|
||||||
|
print("Error: " + str(p.status_code) + " invalid credentials")
|
||||||
|
self.token = None
|
||||||
|
|
||||||
|
|
||||||
|
def reauthorize(self, email, password):
|
||||||
|
"""set new credentials
|
||||||
|
|
||||||
|
Args:
|
||||||
|
email (string): email of the user
|
||||||
|
password (string): password of the user
|
||||||
|
"""
|
||||||
|
payload = {'email': email, 'password': password}
|
||||||
|
with r.Session() as s:
|
||||||
|
p = s.post(self.db_adress + "/user/login", json=payload)
|
||||||
|
if p.status_code == 200:
|
||||||
|
self.token = p.json()["data"]['token']
|
||||||
|
return p.json()["data"]['token']
|
||||||
|
else:
|
||||||
|
self.token = None
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_user(self, user_id, max_retries=10):
|
||||||
|
"""gets the shares of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
json: json of user infos
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.get(self.db_adress + "/user", headers=headers)
|
||||||
|
if(req.status_code == 200):
|
||||||
|
return req.json()["data"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.get_user(user_id, max_retries-1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_users(self, max_retries=10):
|
||||||
|
"""gets all users
|
||||||
|
|
||||||
|
Args:
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: list of users
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token}
|
||||||
|
req = s.get(self.db_adress + "/users", headers=headers)
|
||||||
|
if(req.status_code == 200):
|
||||||
|
return req.json()["data"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.get_all_users(max_retries-1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_keywords(self, user_id, max_retries=10):
|
||||||
|
"""gets the keywords of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: list of keywords
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
keywords = []
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.get(self.db_adress + "/keywords", headers=headers)
|
||||||
|
if(req.status_code == 200):
|
||||||
|
keywords_json = req.json()["data"]
|
||||||
|
for keyword in keywords_json:
|
||||||
|
keywords.append(keyword["keyword"])
|
||||||
|
|
||||||
|
return keywords
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.get_user_keywords(user_id, max_retries-1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def set_keyword(self, user_id, keyword):
|
||||||
|
"""sets the keyword of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
keyword (int): keyword of the user
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.post(self.db_adress + "/keyword", json={"keyword": keyword}, headers=headers)
|
||||||
|
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def delete_keyword(self, user_id, keyword):
|
||||||
|
"""deletes the keyword of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
keyword (string): keyword of the user
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.delete(self.db_adress + "/keyword", json={"keyword": keyword}, headers=headers)
|
||||||
|
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_shares(self, user_id, max_retries=10):
|
||||||
|
"""gets the shares of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: list of shares
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.get(self.db_adress + "/shares", headers=headers)
|
||||||
|
if(req.status_code == 200):
|
||||||
|
shares_json = req.json()["data"]
|
||||||
|
shares = []
|
||||||
|
for share in shares_json:
|
||||||
|
shares.append(share["symbol"])
|
||||||
|
|
||||||
|
return shares
|
||||||
|
|
||||||
|
else:
|
||||||
|
return self.get_user_shares(user_id, max_retries-1)
|
||||||
|
|
||||||
|
|
||||||
|
def set_share(self, user_id, symbol):
|
||||||
|
"""sets the share of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
symbol (string): symbol of the share
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.post(self.db_adress + "/share", json={"symbol": symbol}, headers=headers)
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def delete_share(self, user_id, symbol):
|
||||||
|
"""deletes the share of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
symbol (string): symbol of the share
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.delete(self.db_adress + "/share", json={"symbol": symbol}, headers=headers)
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_transactions(self, user_id, max_retries=10):
|
||||||
|
"""gets the transactions of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: dictionary of transactions
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.get(self.db_adress + "/transactions", headers=headers)
|
||||||
|
|
||||||
|
if req.status_code == 200:
|
||||||
|
transactions_dict = req.json()["data"]
|
||||||
|
return transactions_dict
|
||||||
|
else:
|
||||||
|
return self.get_user_transactions(user_id, max_retries-1)
|
||||||
|
|
||||||
|
|
||||||
|
def set_transaction(self, user_id, comment, isin, count, price, time):
|
||||||
|
"""sets the transaction of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
comment (string): comment of the transaction
|
||||||
|
isin (string): isin of the transaction
|
||||||
|
count (int): count of the transaction
|
||||||
|
price (float): price of the transaction
|
||||||
|
time (string): time of the transaction
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
transaction = {"comment": comment, "count": count, "isin": isin, "price": price, "time": time}
|
||||||
|
req = s.post(self.db_adress + "/transaction", json=transaction, headers=headers)
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
def get_user_portfolio(self, user_id, max_retries=10):
|
||||||
|
"""gets the portfolio of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
max_retries (int): max retries for the request
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: dictionary of portfolio
|
||||||
|
"""
|
||||||
|
if max_retries <= 0:
|
||||||
|
return None
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.get(self.db_adress + "/portfolio", headers=headers)
|
||||||
|
if req.status_code == 200:
|
||||||
|
portfolio_dict = req.json()["data"]
|
||||||
|
return portfolio_dict
|
||||||
|
else:
|
||||||
|
return self.get_user_portfolio(user_id, max_retries-1)
|
||||||
|
|
||||||
|
def set_cron_interval(self, user_id, cron_interval):
|
||||||
|
"""sets the cron interval of the user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (int): id of the user
|
||||||
|
cron_interval (String): Update interval in cron format => see https://crontab.guru/ for formatting
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: status code
|
||||||
|
"""
|
||||||
|
if not croniter.is_valid(cron_interval):
|
||||||
|
print("Error: Invalid cron format")
|
||||||
|
return -1
|
||||||
|
|
||||||
|
with r.Session() as s:
|
||||||
|
headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
|
||||||
|
req = s.put(self.db_adress + "/user/setCron", json={"cron": cron_interval}, headers=headers)
|
||||||
|
return req.status_code
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
print("This is a module for the telegram bot. It is not intended to be run directly.")
|
||||||
|
handler = API_Handler("https://gruppe1.testsites.info/api", "bot@example.com", "bot")
|
||||||
|
print(handler.token)
|
||||||
|
keywords = handler.get_user_keywords(user_id = 1709356058) #user_id is currently mine (Linus)
|
||||||
|
print(keywords)
|
||||||
|
shares = handler.get_user_portfolio(user_id = 1709356058)
|
||||||
|
print("set cron with status: "+ str(handler.set_cron_interval(user_id = 1709356058, cron_interval = "0 0 * * *")))
|
||||||
|
user = handler.get_user(user_id = 1709356058)
|
||||||
|
print(user)
|
||||||
|
all_users = handler.get_all_users()
|
||||||
|
print(all_users)
|
||||||
|
print(shares)
|
||||||
|
sys.exit(1)
|
@ -17,29 +17,36 @@ __license__ = "None"
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import telebot
|
import telebot
|
||||||
import time
|
|
||||||
import sys
|
import sys
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
|
||||||
import news.news_fetcher as news
|
import news.news_fetcher as news
|
||||||
import shares.share_fetcher as share_fetcher
|
import shares.share_fetcher as share_fetcher
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
from telebot import types
|
from telebot import types
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from api_handling.api_handler import API_Handler
|
||||||
|
|
||||||
load_dotenv()
|
|
||||||
|
|
||||||
bot_version = "0.2.1"
|
load_dotenv(dotenv_path='.env')
|
||||||
|
|
||||||
|
bot_version = "1.0.1"
|
||||||
user_list = []
|
user_list = []
|
||||||
|
|
||||||
|
#create api handler
|
||||||
|
api_handler = API_Handler("https://gruppe1.testsites.info/api", str(os.getenv("BOT_EMAIL")), str(os.getenv("BOT_PASSWORD")))
|
||||||
|
print("Webserver Token: " + str(api_handler.token))
|
||||||
|
|
||||||
class User: # Currently saving users in this class to test functionality -> later database
|
class User: # Currently saving users in this class to test functionality -> later database
|
||||||
def __init__(self, p_user_id, p_user_name, p_chat_id):
|
def __init__(self, p_user_id, p_user_name, p_chat_id):
|
||||||
|
|
||||||
""" Initialize a new user
|
""" Initialize a new user
|
||||||
:type self:
|
:type self: User
|
||||||
:param self: for class
|
:param self: object of the class
|
||||||
|
|
||||||
:type p_user_id: int
|
:type p_user_id: int
|
||||||
:param p_user_id: telegram user id
|
:param p_user_id: telegram user id
|
||||||
@ -61,7 +68,7 @@ class User: # Currently saving users in this class to test functionality -> late
|
|||||||
|
|
||||||
bot = telebot.TeleBot(os.getenv('BOT_API_KEY'))
|
bot = telebot.TeleBot(os.getenv('BOT_API_KEY'))
|
||||||
|
|
||||||
@bot.message_handler(commands=['start']) # /start -> saving as new user and sending welcome
|
@bot.message_handler(commands=['start', 'Start']) # /start -> saving as new user and sending welcome
|
||||||
def send_start(message):
|
def send_start(message):
|
||||||
|
|
||||||
""" Description
|
""" Description
|
||||||
@ -83,7 +90,7 @@ def send_start(message):
|
|||||||
bot.reply_to(message, "Welcome to this share bot project. Type /help to get information on what this bot can do")
|
bot.reply_to(message, "Welcome to this share bot project. Type /help to get information on what this bot can do")
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=['version'])
|
@bot.message_handler(commands=['version', 'Version'])
|
||||||
def send_version(message):
|
def send_version(message):
|
||||||
|
|
||||||
""" Sending programm version
|
""" Sending programm version
|
||||||
@ -97,7 +104,7 @@ def send_version(message):
|
|||||||
bot.reply_to(message, bot_version)
|
bot.reply_to(message, bot_version)
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=['help']) # /help -> sending all functions
|
@bot.message_handler(commands=['help', 'Help']) # /help -> sending all functions
|
||||||
def send_welcome(message):
|
def send_welcome(message):
|
||||||
|
|
||||||
""" Send all functions
|
""" Send all functions
|
||||||
@ -108,10 +115,10 @@ def send_welcome(message):
|
|||||||
|
|
||||||
:rtype: none
|
:rtype: none
|
||||||
"""
|
"""
|
||||||
bot.reply_to(message, "/id or /auth for authentication. /update to get updates on your shares. /users to see all users. /news to get current use for your keywords. /share to get price of specific share. For further details see aktienbot.flokaiser.com")
|
bot.reply_to(message, "/id or /auth get your user id\n/update get updates on your shares.\n/users see all users.\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/share get price of specific share\n/portfolio see own portfolio\n/newtransaction add new transaction\n/interval get update interval\n/setinterval set update interval\n_For further details see https://gruppe1.testsites.info _", parse_mode='MARKDOWN')
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=['users'])
|
@bot.message_handler(commands=['users', 'Users']) # /users -> sending all users
|
||||||
def send_all_users(message):
|
def send_all_users(message):
|
||||||
|
|
||||||
""" Send all users, only possible for admins
|
""" Send all users, only possible for admins
|
||||||
@ -133,8 +140,27 @@ def send_all_users(message):
|
|||||||
answer = str(known_user.user_id) + ' : ' + known_user.user_name
|
answer = str(known_user.user_id) + ' : ' + known_user.user_name
|
||||||
bot.send_message(chat_id=user_id, text=answer)
|
bot.send_message(chat_id=user_id, text=answer)
|
||||||
|
|
||||||
|
|
||||||
|
@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'
|
||||||
|
|
||||||
@bot.message_handler(commands=['id', 'auth']) # /auth or /id -> Authentication with user_id over web tool
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
user_data = api_handler.get_user(user_id) # tbd: formatting
|
||||||
|
if not user_data or user_data == None:
|
||||||
|
bot.reply_to(message, "This didn\'t work. Make sure to connect your telegram id (/id) on https://gruppe1.testsites.info")
|
||||||
|
return
|
||||||
|
|
||||||
|
bot.reply_to(message, 'Your user data:\n' + str(user_data))
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['id', 'auth', 'Id', 'Auth']) # /auth or /id -> Authentication with user_id over web tool
|
||||||
def send_id(message):
|
def send_id(message):
|
||||||
|
|
||||||
""" Send user id for authentication with browser
|
""" Send user id for authentication with browser
|
||||||
@ -145,49 +171,72 @@ def send_id(message):
|
|||||||
|
|
||||||
:rtype: none
|
:rtype: none
|
||||||
"""
|
"""
|
||||||
answer = 'Your ID/Authentication Code is: [' + str(message.from_user.id) + ']. Enter this code in the settings on aktienbot.flokaiser.com to get updates on your shares.'
|
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)
|
bot.reply_to(message, answer)
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=['update'])
|
#function that sends telegram status(running or offline) as message from telegram bot to user
|
||||||
def send_update(message):
|
@bot.message_handler(commands=['status', 'Status'])
|
||||||
|
def send_status(message):
|
||||||
""" Send update on shares
|
|
||||||
|
""" Sends status to user
|
||||||
:type message: message object bot
|
:type message: message object bot
|
||||||
:param message: message that was reacted to, in this case always containing '/help'
|
:param message: message that was reacted to, if no other command handler gets called
|
||||||
|
|
||||||
:raises: none
|
:raises: none
|
||||||
|
|
||||||
:rtype: none
|
:rtype: none
|
||||||
"""
|
"""
|
||||||
user_id = int(message.from_user.id)
|
bot.reply_to(message, "bot is running")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['update', 'Update']) # /update -> update shares
|
||||||
|
def update_for_user(message):
|
||||||
|
|
||||||
#Can be deleted when getting from database
|
p_user_id = int(message.from_user.id)
|
||||||
dirname = os.path.dirname(__file__)
|
p_my_handler = api_handler
|
||||||
json_path = os.path.join(dirname, 'shares/shares_example.json')
|
|
||||||
|
|
||||||
with open(json_path) as json_file:
|
share_symbols = []
|
||||||
json_share_data = json.load(json_file)
|
share_amounts = []
|
||||||
int_share_count = int(json_share_data['share_count'])
|
share_courses = []
|
||||||
str_username = str(json_share_data['user'])
|
|
||||||
bot.send_message(chat_id=user_id, text=f'Hello {str_username}. Here is the update on your currently owned shares:')
|
my_portfolio = p_my_handler.get_user_portfolio(p_user_id)
|
||||||
|
|
||||||
|
for element in my_portfolio:
|
||||||
for i in range(int_share_count):
|
if element["count"] != '' and element["symbol"]!= '':
|
||||||
|
print(element["count"], element["symbol"])
|
||||||
my_share = json_share_data['shares'][i]
|
share_symbols.append(element["symbol"])
|
||||||
my_share_symbol = str(my_share['symbol'])
|
share_amounts.append(element["count"])
|
||||||
my_share_amount = float(my_share['amount_bought'])
|
share_courses.append(element["current_price"])
|
||||||
my_share_buy_price = float(my_share['price_bought'])
|
|
||||||
my_share_course = float(share_fetcher.get_share_price(my_share_symbol))
|
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)
|
||||||
|
|
||||||
my_update_message = f'Symbol: {my_share_symbol}\nPrice: {my_share_course}\nBought for: {my_share_buy_price}\n\
|
if len(share_symbols) != 0:
|
||||||
Amount owned: {my_share_amount}\nWin/Lose: {(my_share_amount*my_share_course) - (my_share_amount*my_share_buy_price)}'
|
for i in range(len(share_symbols)):
|
||||||
bot.send_message(chat_id=user_id, text=my_update_message)
|
my_update_message = f'Symbol: {share_symbols[i]}\nCurrent Price per Share: {share_courses[i]}\nAmount owned: {share_amounts[i]}\nTotal Investment: {float(share_courses[i]) * float(share_amounts[i])}'
|
||||||
|
send_to_user(my_update_message, pUser_id=p_user_id)
|
||||||
|
else:
|
||||||
|
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 = 1770205310):
|
||||||
|
|
||||||
|
""" 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'])
|
@bot.message_handler(commands=['share', 'Share']) # /share -> get share price
|
||||||
def send_share_update(message):
|
def send_share_update(message):
|
||||||
|
|
||||||
""" Send price of a specific share
|
""" Send price of a specific share
|
||||||
@ -210,10 +259,49 @@ def send_share_price(message):
|
|||||||
bot.reply_to(message, str_share_price)
|
bot.reply_to(message, str_share_price)
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(commands=['news'])
|
@bot.message_handler(commands=['allnews', 'Allnews']) # /allnews -> get all news
|
||||||
def send_news(message):
|
def send_all_news(message):
|
||||||
|
|
||||||
""" Get news for keywords of user
|
""" Get news for keywords of user
|
||||||
|
:type message: message object bot
|
||||||
|
:param message: message that was reacted to, in this case always containing '/allnews'
|
||||||
|
|
||||||
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
keywords = api_handler.get_user_keywords(user_id)
|
||||||
|
|
||||||
|
if keywords == None:
|
||||||
|
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 keywords:
|
||||||
|
bot.send_message(chat_id=user_id, text='You have no keywords. Please add some keywords with /news')
|
||||||
|
return
|
||||||
|
|
||||||
|
keywords_search = ' OR '.join(keywords)
|
||||||
|
print(keywords_search)
|
||||||
|
now = dt.datetime.now().date()
|
||||||
|
from_date = now - dt.timedelta(days=7)
|
||||||
|
from_date_formatted = dt.datetime.strftime(from_date, '%Y-%m-%d')
|
||||||
|
print(from_date_formatted)
|
||||||
|
news_list = news.get_all_news_by_keyword(keywords_search, from_date_formatted)["articles"]
|
||||||
|
|
||||||
|
if news_list:
|
||||||
|
for article in news_list:
|
||||||
|
formatted_article = news.format_article(article)
|
||||||
|
bot.send_message(chat_id=user_id, text=formatted_article, parse_mode="MARKDOWN")
|
||||||
|
else:
|
||||||
|
bot.send_message(chat_id=user_id, text='No news found for your keywords.')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['news', 'News']) # /news -> get news for specific keyword
|
||||||
|
def send_news(message):
|
||||||
|
""" Get news for keywords of user
|
||||||
|
|
||||||
:type message: message object bot
|
:type message: message object bot
|
||||||
:param message: message that was reacted to, in this case always containing '/news'
|
:param message: message that was reacted to, in this case always containing '/news'
|
||||||
|
|
||||||
@ -221,21 +309,223 @@ def send_news(message):
|
|||||||
|
|
||||||
:rtype: none
|
:rtype: none
|
||||||
"""
|
"""
|
||||||
|
|
||||||
keyword = "bitcoin"
|
|
||||||
user_id = int(message.from_user.id)
|
user_id = int(message.from_user.id)
|
||||||
#Get Information for user with this id
|
keywords = api_handler.get_user_keywords(user_id)
|
||||||
|
|
||||||
articles = news.get_top_news_by_keyword(keyword) #tbd: get keyword from db
|
if keywords == None:
|
||||||
try:
|
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')
|
||||||
formatted_article = news.format_article(articles["articles"][0])
|
|
||||||
except IndexError:
|
|
||||||
bot.send_message(chat_id=user_id, text=f"no news currently available for keyword: {keyword}")
|
|
||||||
return
|
return
|
||||||
bot.send_message(chat_id=user_id, text=f"_keyword: {keyword}_\n\n" + formatted_article, parse_mode="MARKDOWN")
|
|
||||||
|
if not keywords:
|
||||||
|
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"]
|
||||||
|
if top_news == None:
|
||||||
|
bot.send_message(chat_id=user_id, text='News Server did not respond correctly. Try again later.')
|
||||||
|
return
|
||||||
|
if not top_news:
|
||||||
|
bot.send_message(chat_id=user_id, text=f'No news found for keyword: *{keyword}*', parse_mode="MARKDOWN")
|
||||||
|
return
|
||||||
|
|
||||||
|
formatted_article = news.format_article(top_news[0])
|
||||||
|
bot.send_message(chat_id=user_id, text=f"_keyword: {keyword}_\n\n" + formatted_article, parse_mode="MARKDOWN")
|
||||||
|
|
||||||
|
|
||||||
@bot.message_handler(func=lambda message: True) # Returning that command is unkown for any other statement
|
@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)
|
||||||
|
|
||||||
|
def store_keyword(message):
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
print(str(user_id))
|
||||||
|
keyword = str(message.text).lower()
|
||||||
|
status = api_handler.set_keyword(user_id, keyword)
|
||||||
|
if status == 200:
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Keyword "{keyword}" added.')
|
||||||
|
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)
|
||||||
|
|
||||||
|
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:
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Keyword "{keyword}" removed.')
|
||||||
|
else:
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Failed deleting keyword "{keyword}". (statuscode {status})')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['keywords', 'Keywords']) # /keywords -> get keywords of user
|
||||||
|
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)
|
||||||
|
keywords = api_handler.get_user_keywords(user_id)
|
||||||
|
if keywords == None:
|
||||||
|
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 keywords:
|
||||||
|
bot.send_message(chat_id=user_id, text='No keywords set for this account. Add keywords by using /addkeyword')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
keywords_str = ', '.join(keywords)
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Your keywords are: _{keywords_str}_', parse_mode="MARKDOWN")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['portfolio', 'Portfolio']) #tbd
|
||||||
|
def send_portfolio(message):
|
||||||
|
""" Send portfolio of user
|
||||||
|
:type message: message object bot
|
||||||
|
: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)
|
||||||
|
if portfolio == None:
|
||||||
|
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:
|
||||||
|
bot.send_message(chat_id=user_id, text='You do not have any stocks in your portfolio.')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
for stock in portfolio:
|
||||||
|
comment = str(stock["comment"])
|
||||||
|
count = "{:.2f}".format(float(stock["count"]))
|
||||||
|
isin = str(stock["isin"])
|
||||||
|
worth = "{:.2f}".format(float(stock["current_price"]) * float(stock["count"]))
|
||||||
|
bot.send_message(chat_id=user_id, text=f'*{comment}*\n_{isin}_\namount: {count}\nworth: ${worth}', parse_mode="MARKDOWN")
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['newtransaction', 'Newtransaction']) #tbd not working rn
|
||||||
|
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>,<amount>,<price_per_stock_usd>" (time of transaction will be set to now):')
|
||||||
|
bot.register_next_step_handler(message, set_new_transaction_step)
|
||||||
|
|
||||||
|
def set_new_transaction_step(message):
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
|
||||||
|
if not re.match(r"[A-Za-z0-9]+,[A-Za-z0-9]+,[0-9]+(.[0-9]+)?,[0-9]+(.[0-9]+)?", message.text):
|
||||||
|
bot.send_message(chat_id=user_id, text='Invalid format \n(e.g. Apple,US0378331005,53.2,120.4).\n Try again with /newtransaction.')
|
||||||
|
return
|
||||||
|
|
||||||
|
transaction_data = str(message.text).split(',')
|
||||||
|
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()
|
||||||
|
#print("\n\n\n\n\n")
|
||||||
|
#print(f"{symbol},{amount},{price},{time}")
|
||||||
|
status = api_handler.set_transaction(user_id, desc, isin, amount, price, time)
|
||||||
|
|
||||||
|
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})')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['interval', 'Interval']) #tbd
|
||||||
|
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)
|
||||||
|
user_data = api_handler.get_user(user_id)
|
||||||
|
if user_data == None:
|
||||||
|
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:
|
||||||
|
interval = str(user_data['cron'])
|
||||||
|
if interval == 'None':
|
||||||
|
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(' ', '_')
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Your update interval: {interval} (https://crontab.guru/#{formatted_interval})')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(commands=['setinterval', 'Setinterval']) #tbd
|
||||||
|
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
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
bot.send_message(chat_id=user_id, text='Type interval in cron format:\n(https://crontab.guru/)')
|
||||||
|
bot.register_next_step_handler(message, set_new_interval_step)
|
||||||
|
|
||||||
|
def set_new_interval_step(message):
|
||||||
|
|
||||||
|
user_id = int(message.from_user.id)
|
||||||
|
interval = str(message.text)
|
||||||
|
status = api_handler.set_cron_interval(user_id, interval)
|
||||||
|
|
||||||
|
if status == 200:
|
||||||
|
bot.send_message(chat_id=user_id, text='Interval succesfully set.')
|
||||||
|
return
|
||||||
|
|
||||||
|
if status == -1: # only -1 when interval is invalid
|
||||||
|
bot.send_message(chat_id=user_id, text='Invalid interval format. Try again with\n /setinterval.')
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
bot.send_message(chat_id=user_id, text=f'Failed setting interval. (statuscode {status})')
|
||||||
|
|
||||||
|
|
||||||
|
@bot.message_handler(func=lambda message: True) # Returning that command is unknown for any other statement
|
||||||
def echo_all(message):
|
def echo_all(message):
|
||||||
|
|
||||||
""" Tell that command is not known if it is no known command
|
""" Tell that command is not known if it is no known command
|
||||||
@ -274,15 +564,12 @@ def query_text(inline_query):
|
|||||||
|
|
||||||
def main_loop():
|
def main_loop():
|
||||||
|
|
||||||
""" Get Information about bot status every 3 seconds
|
""" Start bot
|
||||||
:raises: none
|
:raises: none
|
||||||
|
|
||||||
:rtype: none
|
:rtype: none
|
||||||
"""
|
"""
|
||||||
bot.infinity_polling()
|
bot.infinity_polling()
|
||||||
while 1:
|
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
try:
|
try:
|
||||||
|
37
telegram_bot/bot_scheduler.py
Normal file
37
telegram_bot/bot_scheduler.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
script for regularly sending updates on shares and news based on user interval
|
||||||
|
"""
|
||||||
|
__author__ = "Florian Kellermann, Linus Eickhoff"
|
||||||
|
__date__ = "05.04.2022"
|
||||||
|
__version__ = "0.0.1"
|
||||||
|
__license__ = "None"
|
||||||
|
|
||||||
|
import shares.share_fetcher as share_fetcher
|
||||||
|
import news.news_fetcher as news_fetcher
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||||
|
|
||||||
|
'''
|
||||||
|
* * * * * code
|
||||||
|
┬ ┬ ┬ ┬ ┬
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ │ │ └──── weekday (0->Monday, 7->Sunday)
|
||||||
|
│ │ │ └────── Month (1-12)
|
||||||
|
│ │ └──────── Day (1-31)
|
||||||
|
│ └────────── Hour (0-23)
|
||||||
|
└──────────── Minute (0-59)
|
||||||
|
|
||||||
|
example 0 8 * * * -> daily update at 8am
|
||||||
|
'''
|
||||||
|
|
||||||
|
def user_updates():
|
||||||
|
"""sends timed updates automatically to user
|
||||||
|
|
||||||
|
Args:
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
|
return
|
177
telegram_bot/bot_updates.py
Normal file
177
telegram_bot/bot_updates.py
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
"""
|
||||||
|
script for regularly sending updates on shares and news based on user interval
|
||||||
|
"""
|
||||||
|
__author__ = "Florian Kellermann, Linus Eickhoff"
|
||||||
|
__date__ = "05.04.2022"
|
||||||
|
__version__ = "1.0.1"
|
||||||
|
__license__ = "None"
|
||||||
|
|
||||||
|
from calendar import month
|
||||||
|
from symtable import Symbol
|
||||||
|
from shares.share_fetcher import get_share_price
|
||||||
|
import time
|
||||||
|
import datetime
|
||||||
|
from bot import bot
|
||||||
|
import sys
|
||||||
|
from multiprocessing import Process
|
||||||
|
from apscheduler.schedulers.background import BackgroundScheduler
|
||||||
|
from api_handling.api_handler import API_Handler
|
||||||
|
|
||||||
|
|
||||||
|
'''
|
||||||
|
* * * * * code
|
||||||
|
┬ ┬ ┬ ┬ ┬
|
||||||
|
│ │ │ │ │
|
||||||
|
│ │ │ │ └──── weekday (0->Monday, 7->Sunday)
|
||||||
|
│ │ │ └────── Month (1-12)
|
||||||
|
│ │ └──────── Day (1-31)
|
||||||
|
│ └────────── Hour (0-23)
|
||||||
|
└──────────── Minute (0-59)
|
||||||
|
|
||||||
|
example 0 8 * * * -> daily update at 8am
|
||||||
|
'''
|
||||||
|
user_ids = []
|
||||||
|
user_crontab = []
|
||||||
|
|
||||||
|
def main_loop():
|
||||||
|
""" main loop for regularly sending updates
|
||||||
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
current_time_datetime = datetime.datetime.now()
|
||||||
|
my_handler = API_Handler("https://gruppe1.testsites.info/api", "bot@example.com", "bot")
|
||||||
|
|
||||||
|
|
||||||
|
# update_for_user(5270256395, my_handler) # Debug (running test update for kevins shares)
|
||||||
|
|
||||||
|
|
||||||
|
update_crontab(current_time_datetime, my_handler)
|
||||||
|
|
||||||
|
|
||||||
|
def update_crontab(pCurrent_Time, p_my_handler):
|
||||||
|
""" Updating crontab lists every hour
|
||||||
|
:type pCurrent_Time: time when starting crontab update
|
||||||
|
:param pCurrent_Time: datetime
|
||||||
|
|
||||||
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
global user_crontab
|
||||||
|
global user_ids
|
||||||
|
|
||||||
|
#p_my_handler.set_cron_interval(user_id = 1770205310, cron_interval = "23 08 * * *")
|
||||||
|
|
||||||
|
all_users = p_my_handler.get_all_users()
|
||||||
|
|
||||||
|
user_ids = []
|
||||||
|
user_crontab = []
|
||||||
|
|
||||||
|
for element in all_users:
|
||||||
|
if element["cron"] != '' and element["telegram_user_id"] != '':
|
||||||
|
user_ids.append(int(element["telegram_user_id"]))
|
||||||
|
user_crontab.append(str(element["cron"]))
|
||||||
|
|
||||||
|
print(user_ids)
|
||||||
|
|
||||||
|
update_based_on_crontab(user_ids, user_crontab, p_my_handler)
|
||||||
|
|
||||||
|
update_crontab(datetime.datetime.now(), p_my_handler)
|
||||||
|
|
||||||
|
|
||||||
|
def update_based_on_crontab(p_user_ids, p_user_crontab, p_my_handler):
|
||||||
|
|
||||||
|
""" Check all the crontab codes and add jobs to start in time
|
||||||
|
:type p_user_ids: array
|
||||||
|
:param p_user_ids: user id array of all users
|
||||||
|
|
||||||
|
:type p_user_crontab: array
|
||||||
|
:param p_user_crontab: crontabs for all users equivalent to the user array
|
||||||
|
|
||||||
|
:type p_my_handler: Api_Handler
|
||||||
|
:param p_my_handler: get database stuff
|
||||||
|
|
||||||
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
|
||||||
|
my_scheduler = BackgroundScheduler()
|
||||||
|
|
||||||
|
print(len(user_ids)) #Debug
|
||||||
|
|
||||||
|
for i in range(len(p_user_ids)):
|
||||||
|
cron_split = p_user_crontab[i].split(" ")
|
||||||
|
print(cron_split[4], cron_split[1], cron_split[0], cron_split[3], cron_split[2])
|
||||||
|
my_scheduler.add_job(update_for_user, 'cron', day_of_week = cron_split[4] , hour= cron_split[1] , minute = cron_split[0], month= cron_split[3] , day=cron_split[2], args=(p_user_ids[i], p_my_handler ))
|
||||||
|
|
||||||
|
my_scheduler.start()
|
||||||
|
|
||||||
|
time.sleep( 600 )
|
||||||
|
my_scheduler.shutdown()
|
||||||
|
|
||||||
|
def update_for_user(p_user_id, p_my_handler):
|
||||||
|
|
||||||
|
""" Pull shares and send updates for specific user id
|
||||||
|
:type p_user_id: integer
|
||||||
|
:param p_user_id: user id of user that shall receive update
|
||||||
|
|
||||||
|
:type p_my_handler: Api_Handler
|
||||||
|
:param p_my_handler: handle the api and pull from database
|
||||||
|
|
||||||
|
:raises: none
|
||||||
|
|
||||||
|
:rtype: none
|
||||||
|
"""
|
||||||
|
share_symbols = []
|
||||||
|
share_amounts = []
|
||||||
|
share_courses = []
|
||||||
|
|
||||||
|
my_portfolio = p_my_handler.get_user_portfolio(p_user_id)
|
||||||
|
|
||||||
|
for element in my_portfolio:
|
||||||
|
if element["count"] != '' and element["symbol"]!= '':
|
||||||
|
print(element["count"], element["symbol"])
|
||||||
|
share_symbols.append(element["symbol"])
|
||||||
|
share_amounts.append(element["count"])
|
||||||
|
share_courses.append(element["current_price"])
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if len(share_symbols) != 0:
|
||||||
|
for i in range(len(share_symbols)):
|
||||||
|
my_update_message = f'Symbol: {share_symbols[i]}\nCurrent Price per Share: {share_courses[i]}\nAmount owned: {share_amounts[i]}\nTotal Investment: {float(share_courses[i]) * float(share_amounts[i])}'
|
||||||
|
send_to_user(my_update_message, pUser_id=p_user_id)
|
||||||
|
else:
|
||||||
|
send_to_user("No shares found for your account. Check https://gruppe1.testsites.info/api to change your settings and add shares.", pUser_id=p_user_id)
|
||||||
|
|
||||||
|
|
||||||
|
def send_to_user(pText, pUser_id = 1770205310):
|
||||||
|
|
||||||
|
""" 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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
print('bot_updates.py starting.')
|
||||||
|
try:
|
||||||
|
main_loop()
|
||||||
|
sys.exit(-1)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
print("Ending")
|
||||||
|
sys.exit(-1)
|
@ -1,15 +0,0 @@
|
|||||||
"""
|
|
||||||
script for database interaction
|
|
||||||
"""
|
|
||||||
__author__ = "Florian Kellermann, Linus Eickhoff"
|
|
||||||
__date__ = "15.03.2022"
|
|
||||||
__version__ = "0.0.1"
|
|
||||||
__license__ = "None"
|
|
||||||
|
|
||||||
# get db_key from env
|
|
||||||
|
|
||||||
class DB_Handler:
|
|
||||||
|
|
||||||
def __init__(self, db_adress):
|
|
||||||
# tbd
|
|
||||||
return
|
|
@ -10,6 +10,7 @@ import sys
|
|||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import requests
|
import requests
|
||||||
|
import datetime as dt
|
||||||
|
|
||||||
from newsapi import NewsApiClient
|
from newsapi import NewsApiClient
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
@ -19,11 +20,31 @@ load_dotenv()
|
|||||||
# Init
|
# Init
|
||||||
api_key = os.getenv('NEWS_API_KEY')
|
api_key = os.getenv('NEWS_API_KEY')
|
||||||
newsapi = NewsApiClient(api_key=api_key)
|
newsapi = NewsApiClient(api_key=api_key)
|
||||||
source_json = requests.get(f"https://newsapi.org/v2/top-headlines/sources?apiKey={api_key}&language=en").json()
|
try:
|
||||||
sources = source_json["sources"]
|
source_json = requests.get(f"https://newsapi.org/v2/top-headlines/sources?apiKey={api_key}&language=en").json()
|
||||||
str_sources = ",".join([source["id"] for source in sources])
|
sources = source_json["sources"]
|
||||||
|
str_sources = ",".join([source["id"] for source in sources])
|
||||||
|
except KeyError:
|
||||||
|
print("Error: Could not get sources")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_news_by_keyword(keyword, from_date="2000-01-01"):
|
||||||
|
"""get all news to keyword
|
||||||
|
Args:
|
||||||
|
keyword (String): keyword for search
|
||||||
|
from_date (String): min date for search
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
JSON/dict: dict containing articles
|
||||||
|
"""
|
||||||
|
top_headlines = newsapi.get_everything(q=keyword, sources=str_sources, language='en', from_param=from_date)
|
||||||
|
if(top_headlines["status"] == "ok"):
|
||||||
|
return top_headlines
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def get_top_news_by_keyword(keyword):
|
def get_top_news_by_keyword(keyword):
|
||||||
"""get top news to keyword
|
"""get top news to keyword
|
||||||
Args:
|
Args:
|
||||||
@ -31,9 +52,13 @@ def get_top_news_by_keyword(keyword):
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
JSON/dict: dict containing articles
|
JSON/dict: dict containing articles
|
||||||
"""
|
"""
|
||||||
top_headlines = newsapi.get_top_headlines(q=keyword, sources=str_sources, language='en')
|
top_headlines = newsapi.get_top_headlines(q=keyword, sources=str_sources, language='en')
|
||||||
return top_headlines
|
if(top_headlines["status"] == "ok"):
|
||||||
|
return top_headlines
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
def format_article(article):
|
def format_article(article):
|
||||||
"""format article for messaging (using markdown syntax)
|
"""format article for messaging (using markdown syntax)
|
||||||
@ -53,8 +78,10 @@ def format_article(article):
|
|||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
print("fetching top news by keyword business...")
|
print("this is a module and should not be run directly")
|
||||||
|
print("fetching top news by keyword bitcoin...")
|
||||||
|
|
||||||
articles = get_top_news_by_keyword("bitcoin")
|
articles = get_all_news_by_keyword("bitcoin")
|
||||||
formatted_article = format_article(articles["articles"][0])
|
formatted_article = format_article(articles["articles"][0])
|
||||||
print(formatted_article)
|
print(formatted_article)
|
||||||
|
sys.exit(1)
|
@ -4,3 +4,6 @@ yfinance~=0.1.70
|
|||||||
newsapi-python~=0.2.6
|
newsapi-python~=0.2.6
|
||||||
python-dotenv~=0.20.0
|
python-dotenv~=0.20.0
|
||||||
requests~=2.27.1
|
requests~=2.27.1
|
||||||
|
APScheduler~=3.9.1
|
||||||
|
croniter~=1.3.4
|
||||||
|
tzlocal==2.1
|
||||||
|
Loading…
Reference in New Issue
Block a user