Reformatting
This commit is contained in:
		@@ -3,6 +3,7 @@
 | 
				
			|||||||
Aktienbot API
 | 
					Aktienbot API
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Development
 | 
					## Development
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Create virtual environment `python -m venv venv env/Scripts/activate`
 | 
					1. Create virtual environment `python -m venv venv env/Scripts/activate`
 | 
				
			||||||
2. Install requirements `pip install -r api/requirements.txt`
 | 
					2. Install requirements `pip install -r api/requirements.txt`
 | 
				
			||||||
3. Set environment variables (see list below)
 | 
					3. Set environment variables (see list below)
 | 
				
			||||||
@@ -10,8 +11,8 @@ Aktienbot API
 | 
				
			|||||||
    2. Or set variables using `export` or `set` commands. (Windows `set`, Linux `export`)
 | 
					    2. Or set variables using `export` or `set` commands. (Windows `set`, Linux `export`)
 | 
				
			||||||
4. Run api `python api/app.py`
 | 
					4. Run api `python api/app.py`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
## Testing
 | 
					## Testing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Create virtual environment `python -m venv venv env/Scripts/activate`
 | 
					1. Create virtual environment `python -m venv venv env/Scripts/activate`
 | 
				
			||||||
2. Install requirements `pip install -r api/requirements.txt`
 | 
					2. Install requirements `pip install -r api/requirements.txt`
 | 
				
			||||||
3. Set environment variables (see list below)
 | 
					3. Set environment variables (see list below)
 | 
				
			||||||
@@ -21,6 +22,7 @@ Aktienbot API
 | 
				
			|||||||
5. Run tests: `python -m pytest -v --cov-report term-missing --cov=app`
 | 
					5. Run tests: `python -m pytest -v --cov-report term-missing --cov=app`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Environment variables
 | 
					## Environment variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
    # Flask secret key
 | 
					    # Flask secret key
 | 
				
			||||||
    SECRET_KEY=
 | 
					    SECRET_KEY=
 | 
				
			||||||
@@ -34,6 +36,7 @@ Aktienbot API
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Docker
 | 
					## Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
docker run -d \
 | 
					docker run -d \
 | 
				
			||||||
    --name aktienbot_api \
 | 
					    --name aktienbot_api \
 | 
				
			||||||
@@ -48,4 +51,5 @@ docker run -d \
 | 
				
			|||||||
    --restart unless-stopped \
 | 
					    --restart unless-stopped \
 | 
				
			||||||
    registry.flokaiser.com/aktienbot/api:latest
 | 
					    registry.flokaiser.com/aktienbot/api:latest
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
or load environment variables from file by using `--env-file <filename>`
 | 
					or load environment variables from file by using `--env-file <filename>`
 | 
				
			||||||
@@ -4,21 +4,19 @@ __credits__ = ["Florian Kaiser", "Florian Kellermann", "Linus Eickhof", "Kevin P
 | 
				
			|||||||
__license__ = "GPL 3.0"
 | 
					__license__ = "GPL 3.0"
 | 
				
			||||||
__version__ = "1.0.0"
 | 
					__version__ = "1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import current_app
 | 
					 | 
				
			||||||
from apiflask import APIFlask
 | 
					from apiflask import APIFlask
 | 
				
			||||||
 | 
					 | 
				
			||||||
from dotenv import load_dotenv
 | 
					 | 
				
			||||||
from flask_cors import CORS
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from app.blueprints.keyword import keyword_blueprint
 | 
					from app.blueprints.keyword import keyword_blueprint
 | 
				
			||||||
from app.blueprints.portfolio import portfolio_blueprint
 | 
					from app.blueprints.portfolio import portfolio_blueprint
 | 
				
			||||||
from app.blueprints.shares import shares_blueprint
 | 
					 | 
				
			||||||
from app.blueprints.share_price import share_price_blueprint
 | 
					from app.blueprints.share_price import share_price_blueprint
 | 
				
			||||||
from app.blueprints.transactions import transaction_blueprint
 | 
					from app.blueprints.shares import shares_blueprint
 | 
				
			||||||
from app.blueprints.telegram import telegram_blueprint
 | 
					from app.blueprints.telegram import telegram_blueprint
 | 
				
			||||||
 | 
					from app.blueprints.transactions import transaction_blueprint
 | 
				
			||||||
from app.blueprints.user import users_blueprint
 | 
					from app.blueprints.user import users_blueprint
 | 
				
			||||||
from app.helper_functions import hash_password
 | 
					from app.helper_functions import hash_password
 | 
				
			||||||
from app.models import *
 | 
					from app.models import *
 | 
				
			||||||
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
 | 
					from flask import current_app
 | 
				
			||||||
 | 
					from flask_cors import CORS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_app(config_filename=None):
 | 
					def create_app(config_filename=None):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,9 @@ __credits__ = ["Florian Kaiser", "Florian Kellermann", "Linus Eickhof", "Kevin P
 | 
				
			|||||||
__license__ = "GPL 3.0"
 | 
					__license__ = "GPL 3.0"
 | 
				
			||||||
__version__ = "1.0.0"
 | 
					__version__ = "1.0.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import current_app
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import jwt
 | 
					import jwt
 | 
				
			||||||
from apiflask import HTTPTokenAuth
 | 
					from apiflask import HTTPTokenAuth
 | 
				
			||||||
 | 
					from flask import current_app
 | 
				
			||||||
 | 
					
 | 
				
			||||||
auth = HTTPTokenAuth()
 | 
					auth = HTTPTokenAuth()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,12 +7,11 @@ __version__ = "1.0.0"
 | 
				
			|||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from apiflask import APIBlueprint, abort
 | 
					from apiflask import APIBlueprint, abort
 | 
				
			||||||
 | 
					from app.auth import auth
 | 
				
			||||||
from app.db import database as db
 | 
					from app.db import database as db
 | 
				
			||||||
from app.helper_functions import make_response, get_email_or_abort_401
 | 
					from app.helper_functions import make_response, get_email_or_abort_401
 | 
				
			||||||
from app.auth import auth
 | 
					 | 
				
			||||||
from app.schema import KeywordResponseSchema, KeywordSchema, DeleteSuccessfulSchema
 | 
					 | 
				
			||||||
from app.models import Keyword
 | 
					from app.models import Keyword
 | 
				
			||||||
 | 
					from app.schema import KeywordResponseSchema, KeywordSchema, DeleteSuccessfulSchema
 | 
				
			||||||
 | 
					
 | 
				
			||||||
keyword_blueprint = APIBlueprint('keyword', __name__, url_prefix='/api')
 | 
					keyword_blueprint = APIBlueprint('keyword', __name__, url_prefix='/api')
 | 
				
			||||||
__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
 | 
					__location__ = os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__)))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,9 +6,8 @@ __version__ = "1.0.0"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import pytest
 | 
					import pytest
 | 
				
			||||||
from app import create_app, db
 | 
					from app import create_app, db
 | 
				
			||||||
from app.models import User, Transaction, Keyword, Share
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from app.helper_functions import hash_password
 | 
					from app.helper_functions import hash_password
 | 
				
			||||||
 | 
					from app.models import User, Transaction, Keyword, Share
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@pytest.fixture(scope='module')
 | 
					@pytest.fixture(scope='module')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ __version__ = "1.0.0"
 | 
				
			|||||||
This file (test_keyword.py) contains the functional tests for the `keyword` blueprint.
 | 
					This file (test_keyword.py) contains the functional tests for the `keyword` blueprint.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tests.functional.helper_functions import get_token
 | 
					from tests.functional.helper_functions import get_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ __version__ = "1.0.0"
 | 
				
			|||||||
This file (test_portfolio.py) contains the functional tests for the `portfolio` blueprint.
 | 
					This file (test_portfolio.py) contains the functional tests for the `portfolio` blueprint.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tests.functional.helper_functions import get_token
 | 
					from tests.functional.helper_functions import get_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ __version__ = "1.0.0"
 | 
				
			|||||||
This file (test_share.py) contains the functional tests for the `share` blueprint.
 | 
					This file (test_share.py) contains the functional tests for the `share` blueprint.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tests.functional.helper_functions import get_token
 | 
					from tests.functional.helper_functions import get_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ __version__ = "1.0.0"
 | 
				
			|||||||
This file (test_telegram.py) contains the functional tests for the `telegram` blueprint.
 | 
					This file (test_telegram.py) contains the functional tests for the `telegram` blueprint.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tests.functional.helper_functions import get_token
 | 
					from tests.functional.helper_functions import get_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,6 +8,7 @@ __version__ = "1.0.0"
 | 
				
			|||||||
This file (test_transaction.py) contains the functional tests for the `transaction` blueprint.
 | 
					This file (test_transaction.py) contains the functional tests for the `transaction` blueprint.
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from tests.functional.helper_functions import get_token
 | 
					from tests.functional.helper_functions import get_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -3,6 +3,7 @@
 | 
				
			|||||||
Aktienbot telegram bot
 | 
					Aktienbot telegram bot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Development
 | 
					## Development
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. Create virtual environment `python -m venv venv`
 | 
					1. Create virtual environment `python -m venv venv`
 | 
				
			||||||
2. Launch venv: `.\venv\Scripts\activate`
 | 
					2. Launch venv: `.\venv\Scripts\activate`
 | 
				
			||||||
3. Install requirements `pip install -r telegram_bot/requirements.txt`
 | 
					3. Install requirements `pip install -r telegram_bot/requirements.txt`
 | 
				
			||||||
@@ -12,6 +13,7 @@ Aktienbot telegram bot
 | 
				
			|||||||
5. Run api `python telegram_bot/bot.py`
 | 
					5. Run api `python telegram_bot/bot.py`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Environment variables
 | 
					## Environment variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
    # Telegram bot api key
 | 
					    # Telegram bot api key
 | 
				
			||||||
    BOT_API_KEY=
 | 
					    BOT_API_KEY=
 | 
				
			||||||
@@ -21,6 +23,7 @@ Aktienbot telegram bot
 | 
				
			|||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Docker
 | 
					## Docker
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
docker run -d \
 | 
					docker run -d \
 | 
				
			||||||
    --name aktienbot_bot \
 | 
					    --name aktienbot_bot \
 | 
				
			||||||
@@ -31,4 +34,5 @@ docker run -d \
 | 
				
			|||||||
    --restart unless-stopped \
 | 
					    --restart unless-stopped \
 | 
				
			||||||
    registry.flokaiser.com/aktienbot/bot:latest
 | 
					    registry.flokaiser.com/aktienbot/bot:latest
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
or load environment variables from file by using `--env-file <filename>`
 | 
					or load environment variables from file by using `--env-file <filename>`
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,14 +9,16 @@ __license__ = "None"
 | 
				
			|||||||
# side-dependencies: none
 | 
					# side-dependencies: none
 | 
				
			||||||
# Work in Progress
 | 
					# Work in Progress
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import requests as r
 | 
					import requests as r
 | 
				
			||||||
from croniter import croniter  # used for checking cron formatting
 | 
					from croniter import croniter  # used for checking cron formatting
 | 
				
			||||||
from dotenv import load_dotenv
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
load_dotenv()  # loads environment vars
 | 
					load_dotenv()  # loads environment vars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# note: for more information about the api visit swagger documentation on https://gruppe1.testsites.info/api/docs#/
 | 
					# note: for more information about the api visit swagger documentation on https://gruppe1.testsites.info/api/docs#/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class API_Handler:
 | 
					class API_Handler:
 | 
				
			||||||
@@ -43,7 +45,6 @@ class API_Handler:
 | 
				
			|||||||
        set_admin(email, is_admin): sets the admin status of the user with the given email
 | 
					        set_admin(email, is_admin): sets the admin status of the user with the given email
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    def __init__(self, db_adress, email, password):
 | 
					    def __init__(self, db_adress, email, password):
 | 
				
			||||||
        """initializes the API_Handler class
 | 
					        """initializes the API_Handler class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -63,7 +64,6 @@ class API_Handler:
 | 
				
			|||||||
                print("Error: " + str(p.status_code) + " invalid credentials")
 | 
					                print("Error: " + str(p.status_code) + " invalid credentials")
 | 
				
			||||||
                self.token = None
 | 
					                self.token = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def reauthorize(self, email, password):  # can be used if token expired
 | 
					    def reauthorize(self, email, password):  # can be used if token expired
 | 
				
			||||||
        """set new credentials
 | 
					        """set new credentials
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +87,6 @@ class API_Handler:
 | 
				
			|||||||
                self.token = None
 | 
					                self.token = None
 | 
				
			||||||
                return None
 | 
					                return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_user(self, user_id, max_retries=10):  # max retries are used recursively if the request fails
 | 
					    def get_user(self, user_id, max_retries=10):  # max retries are used recursively if the request fails
 | 
				
			||||||
        """gets the shares of the user
 | 
					        """gets the shares of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -113,7 +112,6 @@ class API_Handler:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return self.get_user(user_id, max_retries - 1)  # if request fails try again recursively
 | 
					                return self.get_user(user_id, max_retries - 1)  # if request fails try again recursively
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    def get_all_users(self, max_retries=10):
 | 
					    def get_all_users(self, max_retries=10):
 | 
				
			||||||
        """gets all users
 | 
					        """gets all users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -138,7 +136,6 @@ class API_Handler:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return self.get_all_users(max_retries - 1)
 | 
					                return self.get_all_users(max_retries - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_user_keywords(self, user_id, max_retries=10):
 | 
					    def get_user_keywords(self, user_id, max_retries=10):
 | 
				
			||||||
        """gets the keywords of the user
 | 
					        """gets the keywords of the user
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@@ -169,8 +166,6 @@ class API_Handler:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return self.get_user_keywords(user_id, max_retries - 1)
 | 
					                return self.get_user_keywords(user_id, max_retries - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_keyword(self, user_id, keyword):
 | 
					    def set_keyword(self, user_id, keyword):
 | 
				
			||||||
        """sets the keyword of the user
 | 
					        """sets the keyword of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -190,7 +185,6 @@ class API_Handler:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delete_keyword(self, user_id, keyword):
 | 
					    def delete_keyword(self, user_id, keyword):
 | 
				
			||||||
        """deletes the keyword of the user
 | 
					        """deletes the keyword of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -210,7 +204,6 @@ class API_Handler:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_user_shares(self, user_id, max_retries=10):
 | 
					    def get_user_shares(self, user_id, max_retries=10):
 | 
				
			||||||
        """gets the shares of the user
 | 
					        """gets the shares of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -241,7 +234,6 @@ class API_Handler:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return self.get_user_shares(user_id, max_retries - 1)
 | 
					                return self.get_user_shares(user_id, max_retries - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_share(self, user_id, isin, comment):
 | 
					    def set_share(self, user_id, isin, comment):
 | 
				
			||||||
        """sets the share of the user
 | 
					        """sets the share of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -258,10 +250,10 @@ class API_Handler:
 | 
				
			|||||||
        """
 | 
					        """
 | 
				
			||||||
        with r.Session() as s:
 | 
					        with r.Session() as s:
 | 
				
			||||||
            headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
 | 
					            headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
 | 
				
			||||||
            req = s.post(self.db_adress + "/share", json={"comment": comment, "isin": isin}, headers=headers) # set share by setting comment and isin, comment can be the real name of the share e.g. "Apple Inc."
 | 
					            req = s.post(self.db_adress + "/share", json={"comment": comment, "isin": isin},
 | 
				
			||||||
 | 
					                         headers=headers)  # set share by setting comment and isin, comment can be the real name of the share e.g. "Apple Inc."
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def delete_share(self, user_id, isin):
 | 
					    def delete_share(self, user_id, isin):
 | 
				
			||||||
        """deletes the share of the user
 | 
					        """deletes the share of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -280,7 +272,6 @@ class API_Handler:
 | 
				
			|||||||
            req = s.delete(self.db_adress + "/share", json={"isin": str(isin)}, headers=headers)  # to delete a share only the isin is needed because it is unique, shares are not transactions!
 | 
					            req = s.delete(self.db_adress + "/share", json={"isin": str(isin)}, headers=headers)  # to delete a share only the isin is needed because it is unique, shares are not transactions!
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_user_transactions(self, user_id, max_retries=10):
 | 
					    def get_user_transactions(self, user_id, max_retries=10):
 | 
				
			||||||
        """gets the transactions of the user
 | 
					        """gets the transactions of the user
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
@@ -307,7 +298,6 @@ class API_Handler:
 | 
				
			|||||||
            else:
 | 
					            else:
 | 
				
			||||||
                return self.get_user_transactions(user_id, max_retries - 1)
 | 
					                return self.get_user_transactions(user_id, max_retries - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_transaction(self, user_id, comment, isin, count, price, time):
 | 
					    def set_transaction(self, user_id, comment, isin, count, price, time):
 | 
				
			||||||
        """sets the transaction of the user
 | 
					        """sets the transaction of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -328,11 +318,11 @@ class API_Handler:
 | 
				
			|||||||
        with r.Session() as s:
 | 
					        with r.Session() as s:
 | 
				
			||||||
            time = time[:-3] + "Z"  # remove last character and add Z to make it a valid date for db
 | 
					            time = time[:-3] + "Z"  # remove last character and add Z to make it a valid date for db
 | 
				
			||||||
            headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
 | 
					            headers = {'Authorization': 'Bearer ' + self.token + ":" + str(user_id)}
 | 
				
			||||||
            transaction = {"comment": str(comment), "count": float(count), "isin": str(isin), "price": float(price), "time": str(time)} # set transaction as JSON with all the attributes needed according to Swagger docs
 | 
					            transaction = {"comment": str(comment), "count": float(count), "isin": str(isin), "price": float(price),
 | 
				
			||||||
 | 
					                           "time": str(time)}  # set transaction as JSON with all the attributes needed according to Swagger docs
 | 
				
			||||||
            req = s.post(self.db_adress + "/transaction", json=transaction, headers=headers)
 | 
					            req = s.post(self.db_adress + "/transaction", json=transaction, headers=headers)
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def get_user_portfolio(self, user_id, max_retries=10):
 | 
					    def get_user_portfolio(self, user_id, max_retries=10):
 | 
				
			||||||
        """gets the portfolio of the user
 | 
					        """gets the portfolio of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -380,7 +370,6 @@ class API_Handler:
 | 
				
			|||||||
            req = s.put(self.db_adress + "/user/setCron", json={"cron": str(cron_interval)}, headers=headers)  # put not post (see swagger docs)
 | 
					            req = s.put(self.db_adress + "/user/setCron", json={"cron": str(cron_interval)}, headers=headers)  # put not post (see swagger docs)
 | 
				
			||||||
            return req.status_code
 | 
					            return req.status_code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    def set_admin(self, email, is_admin):
 | 
					    def set_admin(self, email, is_admin):
 | 
				
			||||||
        """sets the admin of the user
 | 
					        """sets the admin of the user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,3 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
script for telegram bot and its functions
 | 
					script for telegram bot and its functions
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
@@ -14,24 +13,21 @@ __license__ = "None"
 | 
				
			|||||||
# API Documentation https://core.telegram.org/bots/api
 | 
					# API Documentation https://core.telegram.org/bots/api
 | 
				
			||||||
# Code examples https://github.com/eternnoir/pyTelegramBotAPI#getting-started
 | 
					# Code examples https://github.com/eternnoir/pyTelegramBotAPI#getting-started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import datetime as dt
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import telebot
 | 
					import telebot
 | 
				
			||||||
import sys
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
import logging
 | 
					from telebot import types
 | 
				
			||||||
import re
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import helper_functions as hf
 | 
				
			||||||
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 helper_functions as hf
 | 
					 | 
				
			||||||
import datetime as dt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from telebot import types
 | 
					 | 
				
			||||||
from dotenv import load_dotenv
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from api_handling.api_handler import API_Handler
 | 
					from api_handling.api_handler import API_Handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
load_dotenv(dotenv_path='.env')  # load environment variables
 | 
					load_dotenv(dotenv_path='.env')  # load environment variables
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bot_version = "2.0.1"  # version of bot
 | 
					bot_version = "2.0.1"  # version of bot
 | 
				
			||||||
@@ -42,9 +38,9 @@ print("Webserver Token: " + str(api_handler.token))
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
bot = telebot.TeleBot(os.getenv('BOT_API_KEY'))
 | 
					bot = telebot.TeleBot(os.getenv('BOT_API_KEY'))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['start', 'Start'])
 | 
					@bot.message_handler(commands=['start', 'Start'])
 | 
				
			||||||
def send_start(message):
 | 
					def send_start(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Sending welcome message to new user
 | 
					    """ Sending welcome message to new user
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/start'
 | 
					    :param message: message that was reacted to, in this case always containing '/start'
 | 
				
			||||||
@@ -61,7 +57,6 @@ def send_start(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['version', 'Version'])
 | 
					@bot.message_handler(commands=['version', 'Version'])
 | 
				
			||||||
def send_version(message):
 | 
					def send_version(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Sending programm version
 | 
					    """ Sending programm version
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/version'
 | 
					    :param message: message that was reacted to, in this case always containing '/version'
 | 
				
			||||||
@@ -75,7 +70,6 @@ def send_version(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['help', 'Help'])  # /help -> sending all functions
 | 
					@bot.message_handler(commands=['help', 'Help'])  # /help -> sending all functions
 | 
				
			||||||
def send_help(message):
 | 
					def send_help(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Send all functions
 | 
					    """ Send all functions
 | 
				
			||||||
    :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, in this case always containing '/help'
 | 
				
			||||||
@@ -84,12 +78,12 @@ def send_help(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    :rtype: 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.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
 | 
					@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
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/users'
 | 
					    :param message: message that was reacted to, in this case always containing '/users'
 | 
				
			||||||
@@ -110,7 +104,6 @@ def send_all_users(message):
 | 
				
			|||||||
    bot.send_message(chat_id=user_id, text="There are " + str(user_count) + " users in the database:")
 | 
					    bot.send_message(chat_id=user_id, text="There are " + str(user_count) + " users in the database:")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for user in user_list:
 | 
					    for user in user_list:
 | 
				
			||||||
 | 
					 | 
				
			||||||
        username = user['username']
 | 
					        username = user['username']
 | 
				
			||||||
        email = user['email']
 | 
					        email = user['email']
 | 
				
			||||||
        id = user['telegram_user_id']
 | 
					        id = user['telegram_user_id']
 | 
				
			||||||
@@ -122,7 +115,6 @@ def send_all_users(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['setAdmin', 'SetAdmin', 'setadmin', 'Setadmin'])  # set admin rights to user TBD: not working!!
 | 
					@bot.message_handler(commands=['setAdmin', 'SetAdmin', 'setadmin', 'Setadmin'])  # set admin rights to user TBD: not working!!
 | 
				
			||||||
def set_admin(message):
 | 
					def set_admin(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Set admin rights to user
 | 
					    """ Set admin rights to user
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/setAdmin'
 | 
					    :param message: message that was reacted to, in this case always containing '/setAdmin'
 | 
				
			||||||
@@ -141,6 +133,7 @@ def set_admin(message):
 | 
				
			|||||||
    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
 | 
					    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
 | 
				
			||||||
    bot.register_next_step_handler(message, set_admin_step)
 | 
					    bot.register_next_step_handler(message, set_admin_step)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def set_admin_step(message):
 | 
					def set_admin_step(message):
 | 
				
			||||||
    str_message = str(message.text)
 | 
					    str_message = str(message.text)
 | 
				
			||||||
    args_message = str_message.split(',')  # split message into email and admin rights
 | 
					    args_message = str_message.split(',')  # split message into email and admin rights
 | 
				
			||||||
@@ -190,7 +183,6 @@ def send_user(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['id', 'auth', 'Id', 'Auth'])  # /auth or /id -> Authentication with user_id over web tool
 | 
					@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
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/id' or '/auth'
 | 
					    :param message: message that was reacted to, in this case always containing '/id' or '/auth'
 | 
				
			||||||
@@ -206,7 +198,6 @@ def send_id(message):
 | 
				
			|||||||
# function that can be used to ensure that the bot is online and running
 | 
					# function that can be used to ensure that the bot is online and running
 | 
				
			||||||
@bot.message_handler(commands=['status', 'Status'])
 | 
					@bot.message_handler(commands=['status', 'Status'])
 | 
				
			||||||
def send_status(message):
 | 
					def send_status(message):
 | 
				
			||||||
 | 
					 | 
				
			||||||
    """ Sends status to user
 | 
					    """ Sends status to user
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, if no other command handler gets called
 | 
					    :param message: message that was reacted to, if no other command handler gets called
 | 
				
			||||||
@@ -220,7 +211,6 @@ def send_status(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['update', 'Update'])  # /update -> update shares
 | 
					@bot.message_handler(commands=['update', 'Update'])  # /update -> update shares
 | 
				
			||||||
def update_for_user(message):
 | 
					def update_for_user(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    p_user_id = int(message.from_user.id)
 | 
					    p_user_id = int(message.from_user.id)
 | 
				
			||||||
    p_my_handler = api_handler
 | 
					    p_my_handler = api_handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -248,7 +238,6 @@ def update_for_user(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_to_user(pText, pUser_id):
 | 
					def send_to_user(pText, pUser_id):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Send message to user
 | 
					    """ Send message to user
 | 
				
			||||||
    :type pText: string
 | 
					    :type pText: string
 | 
				
			||||||
    :param pText: Text to send to user
 | 
					    :param pText: Text to send to user
 | 
				
			||||||
@@ -265,7 +254,6 @@ def send_to_user(pText, pUser_id):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['share', 'Share'])  # /share -> get share price
 | 
					@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
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, in this case always containing '/share'
 | 
					    :param message: message that was reacted to, in this case always containing '/share'
 | 
				
			||||||
@@ -279,6 +267,7 @@ def send_share_update(message):
 | 
				
			|||||||
    bot.send_message(chat_id=user_id, text='Send Symbol/ISIN of share or name of company:')
 | 
					    bot.send_message(chat_id=user_id, text='Send Symbol/ISIN of share or name of company:')
 | 
				
			||||||
    bot.register_next_step_handler(message, send_share_price)
 | 
					    bot.register_next_step_handler(message, send_share_price)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def send_share_price(message):
 | 
					def send_share_price(message):
 | 
				
			||||||
    str_share_price = share_fetcher.get_share_information_markdown(str(message.text))
 | 
					    str_share_price = share_fetcher.get_share_information_markdown(str(message.text))
 | 
				
			||||||
    bot.reply_to(message, str_share_price, parse_mode="MARKDOWNV2")
 | 
					    bot.reply_to(message, str_share_price, parse_mode="MARKDOWNV2")
 | 
				
			||||||
@@ -286,7 +275,6 @@ def send_share_price(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(commands=['allnews', 'Allnews'])  # /allnews -> get all news
 | 
					@bot.message_handler(commands=['allnews', 'Allnews'])  # /allnews -> get all news
 | 
				
			||||||
def send_all_news(message):
 | 
					def send_all_news(message):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Get news for keywords of user
 | 
					    """ 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 '/allnews'
 | 
					    :param message: message that was reacted to, in this case always containing '/allnews'
 | 
				
			||||||
@@ -373,6 +361,7 @@ def add_keyword(message):
 | 
				
			|||||||
    bot.send_message(chat_id=user_id, text='Type keyword to add:')
 | 
					    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
 | 
					    bot.register_next_step_handler(message, store_keyword)  # wait for user to send keyword, then call store_keyword function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def store_keyword(message):
 | 
					def store_keyword(message):
 | 
				
			||||||
    user_id = int(message.from_user.id)
 | 
					    user_id = int(message.from_user.id)
 | 
				
			||||||
    keyword = str(message.text).lower()  # lower to ensure Bitcoin and bitcoin is not stored as individual keywords
 | 
					    keyword = str(message.text).lower()  # lower to ensure Bitcoin and bitcoin is not stored as individual keywords
 | 
				
			||||||
@@ -397,6 +386,7 @@ def remove_keyword(message):
 | 
				
			|||||||
    bot.send_message(chat_id=user_id, text='Type keyword to remove:')
 | 
					    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
 | 
					    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):
 | 
					def remove_keyword_step(message):
 | 
				
			||||||
    user_id = int(message.from_user.id)
 | 
					    user_id = int(message.from_user.id)
 | 
				
			||||||
    keyword = str(message.text).lower()
 | 
					    keyword = str(message.text).lower()
 | 
				
			||||||
@@ -503,7 +493,8 @@ def set_new_transaction(message):
 | 
				
			|||||||
    :rtype: none
 | 
					    :rtype: none
 | 
				
			||||||
    """
 | 
					    """
 | 
				
			||||||
    user_id = int(message.from_user.id)
 | 
					    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):')
 | 
					    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):')
 | 
				
			||||||
    bot.register_next_step_handler(message, set_new_transaction_step)
 | 
					    bot.register_next_step_handler(message, set_new_transaction_step)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -609,7 +600,6 @@ def send_shares(message):
 | 
				
			|||||||
            bot.send_message(chat_id=user_id, text=share_fetcher.get_share_information_markdown(element), parse_mode="MARKDOWNV2")
 | 
					            bot.send_message(chat_id=user_id, text=share_fetcher.get_share_information_markdown(element), parse_mode="MARKDOWNV2")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
@bot.message_handler(commands=['setinterval', 'Setinterval'])
 | 
					@bot.message_handler(commands=['setinterval', 'Setinterval'])
 | 
				
			||||||
def set_new_interval(message):
 | 
					def set_new_interval(message):
 | 
				
			||||||
    """ Set new interval for user
 | 
					    """ Set new interval for user
 | 
				
			||||||
@@ -624,8 +614,8 @@ def set_new_interval(message):
 | 
				
			|||||||
    bot.send_message(chat_id=user_id, text='Type interval in cron format:\n(https://crontab.guru/)')
 | 
					    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)  # executes function when user sends message
 | 
					    bot.register_next_step_handler(message, set_new_interval_step)  # executes function when user sends message
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def set_new_interval_step(message):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def set_new_interval_step(message):
 | 
				
			||||||
    user_id = int(message.from_user.id)
 | 
					    user_id = int(message.from_user.id)
 | 
				
			||||||
    interval = str(message.text)
 | 
					    interval = str(message.text)
 | 
				
			||||||
    status = api_handler.set_cron_interval(user_id, interval)  # send cron to db
 | 
					    status = api_handler.set_cron_interval(user_id, interval)  # send cron to db
 | 
				
			||||||
@@ -643,7 +633,6 @@ def set_new_interval_step(message):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.message_handler(func=lambda message: True)  # Returning that command is unknown for any other statement
 | 
					@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
 | 
				
			||||||
    :type message: message object bot
 | 
					    :type message: message object bot
 | 
				
			||||||
    :param message: message that was reacted to, if no other command handler gets called
 | 
					    :param message: message that was reacted to, if no other command handler gets called
 | 
				
			||||||
@@ -661,7 +650,6 @@ telebot.logger.setLevel(logging.DEBUG)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@bot.inline_handler(lambda query: query.query == 'text')  # inline prints for debugging
 | 
					@bot.inline_handler(lambda query: query.query == 'text')  # inline prints for debugging
 | 
				
			||||||
def query_text(inline_query):
 | 
					def query_text(inline_query):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Output in the console about current user actions and status of bot
 | 
					    """ Output in the console about current user actions and status of bot
 | 
				
			||||||
    :type inline_query: 
 | 
					    :type inline_query: 
 | 
				
			||||||
    :param inline_query:
 | 
					    :param inline_query:
 | 
				
			||||||
@@ -679,7 +667,6 @@ def query_text(inline_query):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main_loop():
 | 
					def main_loop():
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Start bot
 | 
					    """ Start bot
 | 
				
			||||||
    :raises: none
 | 
					    :raises: none
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -687,6 +674,7 @@ def main_loop():
 | 
				
			|||||||
    """
 | 
					    """
 | 
				
			||||||
    bot.infinity_polling()
 | 
					    bot.infinity_polling()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        main_loop()
 | 
					        main_loop()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,17 +6,18 @@ __date__ = "10.05.2022"
 | 
				
			|||||||
__version__ = "1.0.2"
 | 
					__version__ = "1.0.2"
 | 
				
			||||||
__license__ = "None"
 | 
					__license__ = "None"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from dotenv import load_dotenv
 | 
					 | 
				
			||||||
import news.news_fetcher as news_fetcher
 | 
					 | 
				
			||||||
import time
 | 
					 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
from bot import bot
 | 
					 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
from apscheduler.schedulers.background import BackgroundScheduler
 | 
					import time
 | 
				
			||||||
from api_handling.api_handler import API_Handler
 | 
					 | 
				
			||||||
import shares.share_fetcher as share_fetcher
 | 
					 | 
				
			||||||
import helper_functions as hf
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from apscheduler.schedulers.background import BackgroundScheduler
 | 
				
			||||||
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import helper_functions as hf
 | 
				
			||||||
 | 
					import news.news_fetcher as news_fetcher
 | 
				
			||||||
 | 
					import shares.share_fetcher as share_fetcher
 | 
				
			||||||
 | 
					from api_handling.api_handler import API_Handler
 | 
				
			||||||
 | 
					from bot import bot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
'''
 | 
					'''
 | 
				
			||||||
* * * * * code
 | 
					* * * * * code
 | 
				
			||||||
@@ -35,6 +36,7 @@ user_crontab = []
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
load_dotenv(dotenv_path='.env')
 | 
					load_dotenv(dotenv_path='.env')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def start_updater():
 | 
					def start_updater():
 | 
				
			||||||
    """ starting function for regularly sending updates
 | 
					    """ starting function for regularly sending updates
 | 
				
			||||||
    :raises: none
 | 
					    :raises: none
 | 
				
			||||||
@@ -46,7 +48,6 @@ def start_updater():
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    my_handler = API_Handler("https://gruppe1.testsites.info/api", str(os.getenv("BOT_EMAIL")), str(os.getenv("BOT_PASSWORD")))
 | 
					    my_handler = API_Handler("https://gruppe1.testsites.info/api", str(os.getenv("BOT_EMAIL")), str(os.getenv("BOT_PASSWORD")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    update_crontab(my_handler)
 | 
					    update_crontab(my_handler)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -76,8 +77,8 @@ def update_crontab(p_my_handler):
 | 
				
			|||||||
                    user_crontab.append(str(element["cron"]))
 | 
					                    user_crontab.append(str(element["cron"]))
 | 
				
			||||||
                except:
 | 
					                except:
 | 
				
			||||||
                    user_ids.pop()
 | 
					                    user_ids.pop()
 | 
				
			||||||
            except: continue
 | 
					            except:
 | 
				
			||||||
                
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    print(user_ids)
 | 
					    print(user_ids)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -87,7 +88,6 @@ def update_crontab(p_my_handler):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_based_on_crontab(p_user_ids, p_user_crontab, 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
 | 
					    """ Check all the crontab codes and add jobs to start in time
 | 
				
			||||||
    :type p_user_ids: array
 | 
					    :type p_user_ids: array
 | 
				
			||||||
    :param p_user_ids: user id array of all users
 | 
					    :param p_user_ids: user id array of all users
 | 
				
			||||||
@@ -115,8 +115,8 @@ def update_based_on_crontab(p_user_ids, p_user_crontab, p_my_handler):
 | 
				
			|||||||
    time.sleep(600)
 | 
					    time.sleep(600)
 | 
				
			||||||
    my_scheduler.shutdown()
 | 
					    my_scheduler.shutdown()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def update_for_user(p_user_id, p_my_handler):
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def update_for_user(p_user_id, p_my_handler):
 | 
				
			||||||
    """ Pull shares and send updates for specific user id
 | 
					    """ Pull shares and send updates for specific user id
 | 
				
			||||||
    :type p_user_id: integer
 | 
					    :type p_user_id: integer
 | 
				
			||||||
    :param p_user_id: user id of user that shall receive update
 | 
					    :param p_user_id: user id of user that shall receive update
 | 
				
			||||||
@@ -153,13 +153,11 @@ def update_for_user(p_user_id, p_my_handler):
 | 
				
			|||||||
    else:
 | 
					    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)
 | 
					        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)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    if len(shares) != 0:  # Send updates on watchlist shares if existing
 | 
					    if len(shares) != 0:  # Send updates on watchlist shares if existing
 | 
				
			||||||
        send_to_user("Your watchlist shares:", pUser_id=p_user_id)
 | 
					        send_to_user("Your watchlist shares:", pUser_id=p_user_id)
 | 
				
			||||||
        for element in shares:
 | 
					        for element in shares:
 | 
				
			||||||
            send_to_user(share_fetcher.get_share_information_markdown(element), pUser_id=p_user_id, md_mode=True)
 | 
					            send_to_user(share_fetcher.get_share_information_markdown(element), pUser_id=p_user_id, md_mode=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    keywords = p_my_handler.get_user_keywords(p_user_id)  # get keywords as array
 | 
					    keywords = p_my_handler.get_user_keywords(p_user_id)  # get keywords as array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (keywords):  # if keywords exist and array is not empty
 | 
					    if (keywords):  # if keywords exist and array is not empty
 | 
				
			||||||
@@ -178,9 +176,7 @@ def update_for_user(p_user_id, p_my_handler):
 | 
				
			|||||||
                send_to_user(f"_keyword: {keyword}_\n\n{news_formatted}", pUser_id=p_user_id, md_mode=True)  # send news with related keyword in Markdown
 | 
					                send_to_user(f"_keyword: {keyword}_\n\n{news_formatted}", pUser_id=p_user_id, md_mode=True)  # send news with related keyword in Markdown
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
def send_to_user(pText, pUser_id, md_mode=False):
 | 
					def send_to_user(pText, pUser_id, md_mode=False):
 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    """ Send message to user
 | 
					    """ Send message to user
 | 
				
			||||||
    :type pText: string
 | 
					    :type pText: string
 | 
				
			||||||
    :param pText: Text to send to user
 | 
					    :param pText: Text to send to user
 | 
				
			||||||
@@ -201,7 +197,6 @@ def send_to_user(pText, pUser_id , md_mode = False):
 | 
				
			|||||||
        bot.send_message(chat_id=pUser_id, text=pText)
 | 
					        bot.send_message(chat_id=pUser_id, text=pText)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        start_updater()
 | 
					        start_updater()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ __date__ = "10.05.2022"
 | 
				
			|||||||
__version__ = "1.0.0"
 | 
					__version__ = "1.0.0"
 | 
				
			||||||
__license__ = "None"
 | 
					__license__ = "None"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def contains_markdownv1_symbols(text):
 | 
					def contains_markdownv1_symbols(text):
 | 
				
			||||||
    """ checks if text contains markdown symbols
 | 
					    """ checks if text contains markdown symbols
 | 
				
			||||||
    :type text: string
 | 
					    :type text: string
 | 
				
			||||||
@@ -57,7 +58,6 @@ def make_markdown_proof(text): # used to avoid errors related to markdown parsem
 | 
				
			|||||||
    text = text.replace("$", "\\$")
 | 
					    text = text.replace("$", "\\$")
 | 
				
			||||||
    text = text.replace("%", "\\%")
 | 
					    text = text.replace("%", "\\%")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
    return text
 | 
					    return text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,14 +6,13 @@ __date__ = "26.04.2022"
 | 
				
			|||||||
__version__ = "1.0.0"
 | 
					__version__ = "1.0.0"
 | 
				
			||||||
__license__ = "None"
 | 
					__license__ = "None"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import requests
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import helper_functions as hf
 | 
					import helper_functions as hf
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
from newsapi import NewsApiClient
 | 
					 | 
				
			||||||
from dotenv import load_dotenv
 | 
					from dotenv import load_dotenv
 | 
				
			||||||
 | 
					from newsapi import NewsApiClient
 | 
				
			||||||
 | 
					
 | 
				
			||||||
load_dotenv()  # loads environment vars
 | 
					load_dotenv()  # loads environment vars
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -29,7 +28,8 @@ try:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
except KeyError:
 | 
					except KeyError:
 | 
				
			||||||
    print("Error: Could not get sources, may be blocked because of too many requests (free newsapi is limited to 100 reqs per day)")
 | 
					    print("Error: Could not get sources, may be blocked because of too many requests (free newsapi is limited to 100 reqs per day)")
 | 
				
			||||||
    str_sources = str("Reuters, bbc, cnn, fox-news, google-news, hacker-news, nytimes, the-huffington-post, the-new-york-times, business-insider, bbc-news, cbc-news, ESPN, fox-sports, google-news-uk, independent, the-wall-street-journal, the-washington-times, time, usa-today")
 | 
					    str_sources = str(
 | 
				
			||||||
 | 
					        "Reuters, bbc, cnn, fox-news, google-news, hacker-news, nytimes, the-huffington-post, the-new-york-times, business-insider, bbc-news, cbc-news, ESPN, fox-sports, google-news-uk, independent, the-wall-street-journal, the-washington-times, time, usa-today")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_all_news_by_keyword(keyword, from_date="2000-01-01"):
 | 
					def get_all_news_by_keyword(keyword, from_date="2000-01-01"):
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,10 +6,11 @@ __date__ = "10.05.2022"
 | 
				
			|||||||
__version__ = "1.0.1"
 | 
					__version__ = "1.0.1"
 | 
				
			||||||
__license__ = "None"
 | 
					__license__ = "None"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import helper_functions as hf
 | 
				
			||||||
import investpy
 | 
					import investpy
 | 
				
			||||||
import pandas
 | 
					import pandas
 | 
				
			||||||
from currency_converter import CurrencyConverter
 | 
					from currency_converter import CurrencyConverter
 | 
				
			||||||
import helper_functions as hf
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_share_price(str_search_for):
 | 
					def get_share_price(str_search_for):
 | 
				
			||||||
    """get stock price per share for company name or isin or symbol
 | 
					    """get stock price per share for company name or isin or symbol
 | 
				
			||||||
@@ -57,6 +58,7 @@ def get_share_price(str_search_for):
 | 
				
			|||||||
        except RuntimeError:
 | 
					        except RuntimeError:
 | 
				
			||||||
            return "None"
 | 
					            return "None"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_share_price_no_currency(str_search_for):
 | 
					def get_share_price_no_currency(str_search_for):
 | 
				
			||||||
    """get stock price per share for company name or isin or symbol no currency
 | 
					    """get stock price per share for company name or isin or symbol no currency
 | 
				
			||||||
    Args:
 | 
					    Args:
 | 
				
			||||||
@@ -67,7 +69,6 @@ def get_share_price_no_currency(str_search_for):
 | 
				
			|||||||
        search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
					        search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
				
			||||||
                                               countries=['germany'], n_results=1)
 | 
					                                               countries=['germany'], n_results=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        
 | 
					 | 
				
			||||||
        recent_data = pandas.DataFrame(search_result.retrieve_recent_data())
 | 
					        recent_data = pandas.DataFrame(search_result.retrieve_recent_data())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        stock_price = recent_data.iloc[-1]["Close"]
 | 
					        stock_price = recent_data.iloc[-1]["Close"]
 | 
				
			||||||
@@ -95,6 +96,7 @@ def get_share_price_no_currency(str_search_for):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        return str_return
 | 
					        return str_return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_share_information(str_search_for):
 | 
					def get_share_information(str_search_for):
 | 
				
			||||||
    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
					    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
				
			||||||
                                           countries=['germany'], n_results=1)
 | 
					                                           countries=['germany'], n_results=1)
 | 
				
			||||||
@@ -103,6 +105,7 @@ def get_share_information(str_search_for):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return str_return
 | 
					    return str_return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_share_information_markdown(str_search_for):
 | 
					def get_share_information_markdown(str_search_for):
 | 
				
			||||||
    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
					    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
				
			||||||
                                           countries=['germany'], n_results=1)
 | 
					                                           countries=['germany'], n_results=1)
 | 
				
			||||||
@@ -110,6 +113,7 @@ def get_share_information_markdown(str_search_for):
 | 
				
			|||||||
    str_return = f'*{hf.make_markdown_proof(search_result.name)}*\n_{hf.make_markdown_proof(search_result.symbol)}_\nworth: {hf.make_markdown_proof(get_share_price(str_search_for))}'
 | 
					    str_return = f'*{hf.make_markdown_proof(search_result.name)}*\n_{hf.make_markdown_proof(search_result.symbol)}_\nworth: {hf.make_markdown_proof(get_share_price(str_search_for))}'
 | 
				
			||||||
    return str_return
 | 
					    return str_return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_share_information_simple(str_search_for):
 | 
					def get_share_information_simple(str_search_for):
 | 
				
			||||||
    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
					    search_result = investpy.search_quotes(text=str_search_for, products=['stocks'],
 | 
				
			||||||
                                           countries=['germany'], n_results=1)
 | 
					                                           countries=['germany'], n_results=1)
 | 
				
			||||||
@@ -117,5 +121,6 @@ def get_share_information_simple(str_search_for):
 | 
				
			|||||||
    str_return = search_result.name + "\n" + search_result.symbol + "\nworth: " + get_share_price(str_search_for)
 | 
					    str_return = search_result.name + "\n" + search_result.symbol + "\nworth: " + get_share_price(str_search_for)
 | 
				
			||||||
    return str_return
 | 
					    return str_return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    print("None")
 | 
					    print("None")
 | 
				
			||||||
		Reference in New Issue
	
	Block a user