diff --git a/.drone.yml b/.drone.yml index 2c4ae1d..b4ab91f 100644 --- a/.drone.yml +++ b/.drone.yml @@ -25,6 +25,10 @@ steps: repo: from_secret: repo_webservice dockerfile: webservice/Dockerfile + when: + branch: + include: + - main - name: publish_bot image: plugins/docker @@ -38,6 +42,10 @@ steps: repo: from_secret: repo_bot dockerfile: telegram_bot/Dockerfile + when: + branch: + include: + - main - name: deploy image: appleboy/drone-ssh @@ -58,3 +66,7 @@ steps: PLUGIN_PASSWORD: from_secret: ssh_password PLUGIN_SCRIPT: /opt/docker/TelegramAktienBot/deploy.sh + when: + branch: + include: + - main diff --git a/.gitignore b/.gitignore index 6df9f3c..1a8385e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .idea/* .env +.env.example env -__pycache__/* -telegram_bot/__pycache__/* -telegram_bot/news/__pycache__/* \ No newline at end of file +Lib +Include +*/*/__pycache__/* +*/__pycache__/* \ No newline at end of file diff --git a/README.md b/README.md index 75ba1f9..96a70d7 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ WebEngineering2 Projekt: Aktien und News Bot für Telegram - Datenbank -> database/* ## Local setup for telegram bot -1. create .env and set API keys etc. (use .env.example as a layout) -2. install required libs via ``pip install -r ./telegram_bot/requirements.txt`` -3. run bot.py via ``python ./telegram_bot/bot.py`` +0. optional: build virtual env by ``python -m venv venv`` + ``env/Scripts/activate`` +2. create .env and set API keys etc. (use .env.example as a layout) +3. install required libs via ``pip install -r ./telegram_bot/requirements.txt`` +4. run bot.py via ``python ./telegram_bot/bot.py`` diff --git a/telegram_bot/Dockerfile b/telegram_bot/Dockerfile index df6b0ce..dc51065 100644 --- a/telegram_bot/Dockerfile +++ b/telegram_bot/Dockerfile @@ -1,7 +1,6 @@ -FROM python:3.10-alpine +FROM python:3.10-slim WORKDIR /srv/flask_app -RUN apk add build-base jpeg-dev zlib-dev musl-dev linux-headers g++ COPY telegram_bot/requirements.txt /srv/flask_app/ diff --git a/telegram_bot/api_handler.py b/telegram_bot/api_handler.py new file mode 100644 index 0000000..69c4974 --- /dev/null +++ b/telegram_bot/api_handler.py @@ -0,0 +1,7 @@ +""" +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" \ No newline at end of file diff --git a/telegram_bot/bot.py b/telegram_bot/bot.py index 26ff3e4..95692e2 100644 --- a/telegram_bot/bot.py +++ b/telegram_bot/bot.py @@ -20,17 +20,22 @@ import telebot import time import sys import logging +import json import news.news_fetcher as news +<<<<<<< HEAD import share_fetcher +======= +import shares.share_fetcher as share_fetcher +>>>>>>> 2961bbb4294b603c694edd0bf0ec74661641b833 from telebot import types from dotenv import load_dotenv -from telegram_bot.share_fetcher import Share_Handler + load_dotenv() -bot_version = "0.1.1" +bot_version = "0.2.1" user_list = [] class User: # Currently saving users in this class to test functionality -> later database @@ -107,7 +112,7 @@ def send_welcome(message): :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. For further details see aktienbot.flokaiser.com") + 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.message_handler(commands=['users']) @@ -148,7 +153,7 @@ def send_id(message): bot.reply_to(message, answer) -@bot.message_handler(commands=['update']) # /update -> send static update via user_id to this user, later fetch from database +@bot.message_handler(commands=['update']) def send_update(message): """ Send update on shares @@ -161,11 +166,52 @@ def send_update(message): """ user_id = int(message.from_user.id) - share_fetcher = Share_Handler() + #Can be deleted when getting from database + dirname = os.path.dirname(__file__) + json_path = os.path.join(dirname, 'shares/shares_example.json') + + with open(json_path) as json_file: + json_share_data = json.load(json_file) + int_share_count = int(json_share_data['share_count']) + 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:') + + + for i in range(int_share_count): + + my_share = json_share_data['shares'][i] + my_share_symbol = str(my_share['symbol']) + my_share_amount = float(my_share['amount_bought']) + my_share_buy_price = float(my_share['price_bought']) + my_share_course = float(share_fetcher.get_share_price(my_share_symbol)) + + + my_update_message = f'Symbol: {my_share_symbol}\nPrice: {my_share_course}\nBought for: {my_share_buy_price}\n\ +Amount owned: {my_share_amount}\nWin/Lose: {(my_share_amount*my_share_course) - (my_share_amount*my_share_buy_price)}' + bot.send_message(chat_id=user_id, text=my_update_message) + + +@bot.message_handler(commands=['share']) +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) #Get Information for user with this id - #call Share_Handler - bot.send_message(chat_id=user_id, text='This is your update') + bot.send_message(chat_id=user_id, text='Send symbol of share:') + #str_share_price = shares.wait_for_share.main_loop(bot) + bot.register_next_step_handler(message, send_share_price) + +def send_share_price(message): + str_share_price = share_fetcher.get_share_price(str(message.text)) + bot.reply_to(message, str_share_price) @bot.message_handler(commands=['news']) @@ -180,7 +226,7 @@ def send_news(message): :rtype: none """ - keyword = "business" + keyword = "bitcoin" user_id = int(message.from_user.id) #Get Information for user with this id diff --git a/telegram_bot/news/news_fetcher.py b/telegram_bot/news/news_fetcher.py index 836b2fe..69c0807 100644 --- a/telegram_bot/news/news_fetcher.py +++ b/telegram_bot/news/news_fetcher.py @@ -9,8 +9,7 @@ __license__ = "None" import sys import os import json - -import pandas as pd +import requests from newsapi import NewsApiClient from dotenv import load_dotenv @@ -18,11 +17,12 @@ from dotenv import load_dotenv load_dotenv() # Init -newsapi = NewsApiClient(api_key=os.getenv('NEWS_API_KEY')) - - -# /v2/top-headlines/sources -sources = newsapi.get_sources() +api_key = os.getenv('NEWS_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() +sources = source_json["sources"] +str_sources = ",".join([source["id"] for source in sources]) + def get_top_news_by_keyword(keyword): """get top news to keyword @@ -32,7 +32,7 @@ def get_top_news_by_keyword(keyword): Returns: JSON/dict: dict containing articles """ - top_headlines = newsapi.get_top_headlines(q=keyword, sources='bbc-news,the-verge,cnn', language='en') + top_headlines = newsapi.get_top_headlines(q=keyword, sources=str_sources, language='en') return top_headlines def format_article(article): @@ -55,6 +55,6 @@ if __name__ == '__main__': print("fetching top news by keyword business...") - articles = get_top_news_by_keyword("business") + articles = get_top_news_by_keyword("bitcoin") formatted_article = format_article(articles["articles"][0]) print(formatted_article) \ No newline at end of file diff --git a/telegram_bot/requirements.txt b/telegram_bot/requirements.txt index e81b367..4dcfe5c 100644 --- a/telegram_bot/requirements.txt +++ b/telegram_bot/requirements.txt @@ -1,8 +1,6 @@ pyTelegramBotAPI~=4.4.0 -beautifulsoup4==4.10.0 -Markdown==3.3.6 -Pillow==9.0.1 -yfinance==0.1.70 -newsapi-python -pandas~=1.4.1 +Markdown~=3.3.6 +yfinance~=0.1.70 +newsapi-python~=0.2.6 python-dotenv~=0.19.2 +requests~=2.27.1 diff --git a/telegram_bot/share_fetcher.py b/telegram_bot/share_fetcher.py deleted file mode 100644 index 3fc7c9d..0000000 --- a/telegram_bot/share_fetcher.py +++ /dev/null @@ -1,56 +0,0 @@ -""" -script for share fetching (by symbols (e.g. AAPL, TSLA etc.)) -""" -__author__ = "Florian Kellermann, Linus Eickhoff" -__date__ = "15.03.2022" -__version__ = "0.0.2" -__license__ = "None" - -import yfinance - -# S3W03GQH43I8O6IG - -class Share_Handler: - def __init__(self): - return - - def all_share_prices_for_user(self, int_user_id): - - """ Get all share prices for a certain user with his id - :type int_user_id: integer - :param int_user_id: user_id to get all share prices for - - :raises: none - - :rtype: ###tbd### (maybe dictonary) - """ - return - - - def get_share_price(self, str_symbol): - - """ get current share price for a certain symbol - :type str_symbol: string - :param str_symbol: share symbol to get price for - - :raises: - - :rtype: - """ - - my_share_info = yfinance.Ticker(str_symbol) - my_share_data = my_share_info.info - my_return_string = f'{my_share_data["regularMarketPrice"]} {my_share_data["currency"]}' - return my_return_string - - -if __name__ == '__main__': - - """ test object and get share price - :raises: none - - :rtype: none - """ - - new_handler = Share_Handler() - print(new_handler.get_share_price("TL0.DE")) \ No newline at end of file diff --git a/telegram_bot/shares/share_fetcher.py b/telegram_bot/shares/share_fetcher.py new file mode 100644 index 0000000..1aa3376 --- /dev/null +++ b/telegram_bot/shares/share_fetcher.py @@ -0,0 +1,27 @@ +""" +script for share fetching (by symbols (e.g. AAPL, TSLA etc.)) +""" +__author__ = "Florian Kellermann, Linus Eickhoff" +__date__ = "15.03.2022" +__version__ = "0.0.2" +__license__ = "None" + +import yfinance +import json + +def get_share_price(str_symbol): + + """ get current share price for a certain symbol + :type str_symbol: string + :param str_symbol: share symbol to get price for + + :raises: + + :rtype: + """ + + my_share_info = yfinance.Ticker(str_symbol) + my_share_data = my_share_info.info + #my_return_string = f'{my_share_data["regularMarketPrice"]} {my_share_data["currency"]}' + my_return_string = f'{my_share_data["regularMarketPrice"]}' + return my_return_string \ No newline at end of file diff --git a/telegram_bot/shares/shares_example.json b/telegram_bot/shares/shares_example.json new file mode 100644 index 0000000..3b3b2fc --- /dev/null +++ b/telegram_bot/shares/shares_example.json @@ -0,0 +1,16 @@ +{ + "user": "FloKell", + "share_count": 2, + "shares": [ + { + "symbol": "APC.DE", + "price_bought": "50.06", + "amount_bought": "5.1" + }, + { + "symbol": "TL0.DE", + "price_bought": "450.06", + "amount_bought": "5.13" + } + ] +} \ No newline at end of file