From ffd035dfbf70d4d0a8f9d88b695cc6d9d7281222 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Thu, 23 Dec 2021 14:46:51 +0000 Subject: [PATCH] Switch from Flask to Klein --- handler/__init__.py | 20 ---------- handler/app.py | 96 +++++++++++++++++++++++++++++++++++++++++++++ handler/main.py | 49 ----------------------- 3 files changed, 96 insertions(+), 69 deletions(-) delete mode 100644 handler/__init__.py create mode 100644 handler/app.py delete mode 100644 handler/main.py diff --git a/handler/__init__.py b/handler/__init__.py deleted file mode 100644 index d11e2ad..0000000 --- a/handler/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -from flask import Flask -from flask_sqlalchemy import SQLAlchemy - -# init SQLAlchemy so we can use it later in our models -db = SQLAlchemy() - - -def create_app(): - app = Flask(__name__) - - app.config["SECRET_KEY"] = "4c7c2f455ffa53edf78d2b2e9c3f24f6f9340975" - app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite" - - db.init_app(app) - - from .main import main as main_blueprint - - app.register_blueprint(main_blueprint) - - return app diff --git a/handler/app.py b/handler/app.py new file mode 100644 index 0000000..d5ec232 --- /dev/null +++ b/handler/app.py @@ -0,0 +1,96 @@ +from twisted.logger import Logger +from twisted.internet import reactor +from twisted.internet.task import LoopingCall, deferLater +from klein import Klein + +from json import dumps, loads +from json.decoder import JSONDecodeError + +import pprint +import requests + +from settings import refresh_token, client_id, jwt + +token_refresh_sec = 30 + +api_base = "https://sandbox-b2b.revolut.com/api/1.0" +webhook_url = "https://callback-sandbox.pathogen.is/callback" + +# SYSTEM VARIABLES BELOW # +app = Klein() + +access_token = "" + +log = Logger() + +pp = pprint.PrettyPrinter(indent=2) + + +def get_new_token(): + headers = {"Content-Type": "application/x-www-form-urlencoded"} + data = { + "grant_type": "refresh_token", + "refresh_token": refresh_token, + "client_id": client_id, + "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", + "client_assertion": jwt, + } + r = requests.post(f"{api_base}/auth/token", data=data, headers=headers) + parsed = r.json() + if r.status_code == 200: + if "access_token" in parsed.keys(): + access_token = parsed["access_token"] + if len(access_token) == len(refresh_token): + log.info("Refreshed access token") + return True + else: + log.error(f"Token refresh didn't contain access token: {parsed}", parsed=parsed) + return False + else: + log.error(f"Cannot refresh token: {parsed}", parsed=parsed) + return False + + +def transaction(sender, source_currency, dest_currency, source_amount, dest_amount): + pass + +def setup_webhook(): + log.info("Setting up webhook") + headers = {"Authorization": f"Bearer {access_token}"} + data = { + "url": webhook_url + } + r = requests.post (f"{api_base}/webhook", data=data, headers=headers) + parsed = r.json() + if r.status_code == 200: + log.info("Set up webhook") + return dumps({"success": True}) + else: + log.info("Failed setting up webhook") + + +@app.route("/refresh", methods=["GET"]) +def refresh(request): + rtrn = get_new_token() + return dumps({"success": rtrn}) + + +@app.route("/callback", methods=["POST"]) +def callback(request): + content = request.content.read() + try: + parsed = loads(content) + except JSONDecodeError: + log.error("Failed to parse JSON callback: {content}", content=content) + return dumps({"success": False}) + log.info("Callback received: {parsed}", parsed=parsed) + return dumps({"success": True}) + + +# Set up loop to refresh token, but get one first +deferLater(reactor, 1, get_new_token) +deferLater(reactor, 2, setup_webhook) +lc = LoopingCall(get_new_token) +lc.start(token_refresh_sec) +resource = app.resource +app.run("127.0.0.1", 8080) diff --git a/handler/main.py b/handler/main.py deleted file mode 100644 index 69f68b8..0000000 --- a/handler/main.py +++ /dev/null @@ -1,49 +0,0 @@ -from flask import Blueprint, request, jsonify -import pprint -import requests - -from .settings import * - -# SYSTEM VARIABLES BELOW # -access_token = "" - -main = Blueprint("main", __name__) - -pp = pprint.PrettyPrinter(indent=2) - -def get_new_token(): - headers = {"Content-Type": "application/x-www-form-urlencoded"} - data = { - "grant_type": "refresh_token", - "refresh_token": refresh_token, - "client_id": client_id, - "client_assertion_type": "urn:ietf:params:oauth:client-assertion-type:jwt-bearer", - "client_assertion": jwt, - } - r = requests.post(f"{api_base}/auth/token", data=data, headers=headers) - parsed = r.json() - if r.status_code == 200: - if "access_token" in parsed.keys(): - access_token = parsed["access_token"] - if len(access_token) == len(refresh_token): - return True - else: - main.logger.error(f"Token refresh didn't contain access token: {parsed}") - return False - else: - main.logger.error(f"Cannot refresh token: {parsed}") - return False - - -@main.route("/refresh", methods=["GET"]) -def refresh(): - rtrn = get_new_token() - return jsonify(success=rtrn) - - -@main.route("/callback", methods=["POST"]) -def callback(): - pp.pprint(request.json) - if request.json is None: - return jsonify(success=False) - return jsonify(success=True)