# This file is part of GNU TALER. # Copyright (C) 2017 Taler Systems SA # # TALER is free software; you can redistribute it and/or modify it under the # terms of the GNU Lesser General Public License as published by the Free Software # Foundation; either version 2.1, or (at your option) any later version. # # TALER is distributed in the hope that it will be useful, but WITHOUT ANY # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR # A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public License along with # GNU TALER; see the file COPYING. If not, see # # @author Marcello Stanisci import os import base64 import logging import json from urllib.parse import urljoin import flask import requests import traceback from ..talerconfig import TalerConfig BASE_DIR = os.path.dirname(os.path.abspath(__file__)) app = flask.Flask(__name__, template_folder=BASE_DIR) app.debug = True app.secret_key = base64.b64encode(os.urandom(64)).decode('utf-8') TC = TalerConfig.from_env() BACKEND_URL = TC["frontends"]["backend"].value_string(required=True) CURRENCY = TC["taler"]["currency"].value_string(required=True) APIKEY = TC["frontends"]["backend_apikey"].value_string(required=True) app.config.from_object(__name__) LOGGER = logging.getLogger(__name__) def backend_error(requests_response): LOGGER.error("Backend error: status code: " + str(requests_response.status_code)) try: return flask.jsonify(requests_response.json()), requests_response.status_code except json.decoder.JSONDecodeError: LOGGER.error("Backend error (NO JSON returned): status code: " + str(requests_response.status_code)) return flask.jsonify(dict(error="Backend died, no JSON got from it")), 502 @app.context_processor def utility_processor(): def env(name, default=None): return os.environ.get(name, default) return dict(env=env) def err_abort(abort_status_code, **params): t = flask.render_template("templates/error.html", **params) flask.abort(flask.make_response(t, abort_status_code)) def backend_post(endpoint, json): headers = {"Authorization": "ApiKey " + APIKEY} try: resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json, headers=headers) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: response_json = resp.json() except ValueError: err_abort(500, message="Could not parse response from backend", status_code=resp.status_code) if resp.status_code != 200: err_abort(500, message="Backend returned error status", json=response_json, status_code=resp.status_code) return response_json def backend_get(endpoint, params): headers = {"Authorization": "ApiKey " + APIKEY} try: resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params, headers=headers) except requests.ConnectionError: err_abort(500, message="Could not establish connection to backend") try: response_json = resp.json() except ValueError: err_abort(500, message="Could not parse response from backend") if resp.status_code != 200: err_abort(500, message="Backend returned error status", json=response_json, status_code=resp.status_code) return response_json @app.errorhandler(Exception) def internal_error(e): return flask.render_template("templates/error.html", message="Internal error", stack=traceback.format_exc()) @app.route("/favicon.ico") def favicon(): print("will look into: " + os.path.join(app.root_path, 'static')) return flask.send_from_directory(os.path.join(app.root_path, 'static'), "favicon.ico", mimetype="image/vnd.microsoft.ico") @app.route("/survey-stats", methods=["GET"]) def survey_stats(): stats = backend_get("tip-query", dict(instance="default")) return flask.render_template("templates/survey_stats.html", stats=stats) @app.route("/submit-survey", methods=["POST"]) def submit_survey(): tip_spec = dict(amount=CURRENCY + ":1.0", next_url=os.environ.get("TALER_ENV_URL_INTRO", "https://taler.net/"), instance="default", justification="Payment methods survey") resp = backend_post("tip-authorize", tip_spec) if resp.get("tip_redirect_url"): return flask.redirect(resp["tip_redirect_url"]) err_abort(500, message="Tipping failed, unexpected backend response", json=resp) @app.route("/", methods=["GET"]) def index(): return flask.render_template("templates/index.html", merchant_currency=CURRENCY)