summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.style.yapf5
-rw-r--r--talerdonations/donations/donations.py76
-rw-r--r--talerdonations/talerconfig.py95
-rw-r--r--talerdonations/tests.py1
4 files changed, 116 insertions, 61 deletions
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 0000000..3b39780
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,5 @@
+[style]
+based_on_style = pep8
+coalesce_brackets=True
+column_limit=80
+dedent_closing_brackets=True
diff --git a/talerdonations/donations/donations.py b/talerdonations/donations/donations.py
index f0f97c5..5655734 100644
--- a/talerdonations/donations/donations.py
+++ b/talerdonations/donations/donations.py
@@ -53,6 +53,7 @@ app.config.from_object(__name__)
def utility_processor():
def env(name, default=None):
return os.environ.get(name, default)
+
return dict(env=env)
@@ -76,7 +77,9 @@ def err_abort(abort_status_code, **params):
def backend_get(endpoint, params):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.get(urljoin(BACKEND_URL, endpoint), params=params, headers=headers)
+ 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:
@@ -84,8 +87,10 @@ def backend_get(endpoint, params):
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)
+ err_abort(500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code)
return response_json
@@ -100,21 +105,25 @@ def backend_get(endpoint, params):
def backend_post(endpoint, json):
headers = {"Authorization": "ApiKey " + APIKEY}
try:
- resp = requests.post(urljoin(BACKEND_URL, endpoint), json=json, headers=headers)
+ 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",
+ 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)
+ err_abort(500,
+ message="Backend returned error status",
+ json=response_json,
+ status_code=resp.status_code)
return response_json
-
##
# Inspect GET arguments in the look for a parameter.
#
@@ -126,6 +135,7 @@ def expect_parameter(name):
return err_abort(400, message="parameter '{}' required".format(name))
return val
+
##
# "Fallback" exception handler to capture all the unmanaged errors.
#
@@ -138,13 +148,16 @@ def internal_error(e):
message="Internal error",
stack=traceback.format_exc())
+
##
# Serve the main index page.
#
# @return response object of the index page.
@app.route("/")
def index():
- return flask.render_template("templates/index.html", merchant_currency=CURRENCY)
+ return flask.render_template("templates/index.html",
+ merchant_currency=CURRENCY)
+
##
# Serve the "/javascript" page.
@@ -155,7 +168,6 @@ def javascript_licensing():
return flask.render_template("templates/javascript.html")
-
##
# Serve the "/checkout" page. This page lets the
# user pick the payment method they want to use,
@@ -167,12 +179,11 @@ def checkout():
amount = expect_parameter("donation_amount")
donation_receiver = expect_parameter("donation_receiver")
donation_donor = expect_parameter("donation_donor")
- return flask.render_template(
- "templates/checkout.html",
- donation_amount=amount,
- donation_receiver=donation_receiver,
- donation_donor=donation_donor,
- merchant_currency=CURRENCY)
+ return flask.render_template("templates/checkout.html",
+ donation_amount=amount,
+ donation_receiver=donation_receiver,
+ donation_donor=donation_donor,
+ merchant_currency=CURRENCY)
##
@@ -182,8 +193,7 @@ def checkout():
# @return response object about the mentioned impossibility.
@app.route("/provider-not-supported")
def provider_not_supported():
- return flask.render_template( "templates/provider-not-supported.html")
-
+ return flask.render_template("templates/provider-not-supported.html")
##
@@ -201,18 +211,24 @@ def donate():
payment_system = expect_parameter("payment_system")
if payment_system != "taler":
return flask.redirect(flask.url_for("provider_not_supported"))
- fulfillment_url = flask.url_for("fulfillment", receiver=donation_receiver, _external=True)
+ fulfillment_url = flask.url_for("fulfillment",
+ receiver=donation_receiver,
+ _external=True)
order = dict(
amount=donation_amount,
- extra=dict(donor=donation_donor, receiver=donation_receiver, amount=donation_amount),
+ extra=dict(donor=donation_donor,
+ receiver=donation_receiver,
+ amount=donation_amount),
fulfillment_url=fulfillment_url,
instance=donation_receiver,
summary="Donation to {}".format(donation_receiver),
)
order_resp = backend_post("order", dict(order=order))
order_id = order_resp["order_id"]
- return flask.redirect(flask.url_for("fulfillment", receiver=donation_receiver, order_id=order_id))
-
+ return flask.redirect(
+ flask.url_for("fulfillment",
+ receiver=donation_receiver,
+ order_id=order_id))
##
@@ -226,8 +242,7 @@ def donate():
@app.route("/donation/<receiver>")
def fulfillment(receiver):
order_id = expect_parameter("order_id")
- pay_params = dict(instance=receiver,
- order_id=order_id)
+ pay_params = dict(instance=receiver, order_id=order_id)
pay_status = backend_get("check-payment", pay_params)
if pay_status.get("payment_redirect_url"):
@@ -235,13 +250,12 @@ def fulfillment(receiver):
if pay_status.get("paid"):
extra = pay_status["contract_terms"]["extra"]
- return flask.render_template(
- "templates/fulfillment.html",
- donation_receiver=extra["receiver"],
- donation_amount=extra["amount"],
- donation_donor=extra["donor"],
- order_id=order_id,
- currency=CURRENCY)
+ return flask.render_template("templates/fulfillment.html",
+ donation_receiver=extra["receiver"],
+ donation_amount=extra["amount"],
+ donation_donor=extra["donor"],
+ order_id=order_id,
+ currency=CURRENCY)
# no pay_redirect but article not paid, this should never happen!
err_abort(500, message="Internal error, invariant failed", json=pay_status)
diff --git a/talerdonations/talerconfig.py b/talerdonations/talerconfig.py
index 4a44c97..7959ec2 100644
--- a/talerdonations/talerconfig.py
+++ b/talerdonations/talerconfig.py
@@ -38,17 +38,20 @@ try:
except ImportError:
pass
+
##
# Exception class for a any configuration error.
class ConfigurationError(Exception):
pass
+
##
# Exception class for malformed strings having with parameter
# expansion.
class ExpansionSyntaxError(Exception):
pass
+
##
# Do shell-style parameter expansion.
# Supported syntax:
@@ -80,7 +83,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
end += 1
if balance != 0:
raise ExpansionSyntaxError("unbalanced parentheses")
- piece = var[start+2:end-1]
+ piece = var[start + 2:end - 1]
if piece.find(":-") > 0:
varname, alt = piece.split(":-", 1)
replace = getter(varname)
@@ -93,9 +96,9 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
replace = var[start:end]
else:
end = start + 2
- while end < len(var) and var[start+1:end+1].isalnum():
+ while end < len(var) and var[start + 1:end + 1].isalnum():
end += 1
- varname = var[start+1:end]
+ varname = var[start + 1:end]
replace = getter(varname)
if replace is None:
replace = var[start:end]
@@ -104,6 +107,7 @@ def expand(var: str, getter: Callable[[str], str]) -> str:
return result + var[pos:]
+
##
# A configuration entry.
class Entry:
@@ -164,11 +168,14 @@ class Entry:
if self.value is None:
if warn:
if default is not None:
- LOGGER.warning("Configuration is missing option '%s' in section '%s',\
- falling back to '%s'", self.option, self.section, default)
+ LOGGER.warning(
+ "Configuration is missing option '%s' in section '%s',\
+ falling back to '%s'", self.option,
+ self.section, default)
else:
- LOGGER.warning("Configuration ** is missing option '%s' in section '%s'",
- self.option.upper(), self.section.upper())
+ LOGGER.warning(
+ "Configuration ** is missing option '%s' in section '%s'",
+ self.option.upper(), self.section.upper())
return default
return self.value
@@ -190,6 +197,7 @@ class Entry:
except ValueError:
raise ConfigurationError("Expected number for option '%s' in section '%s'" \
% (self.option.upper(), self.section.upper()))
+
##
# Fetch value to substitute to expansion variables.
#
@@ -231,6 +239,7 @@ class Entry:
return "<unknown>"
return "%s:%s" % (self.filename, self.lineno)
+
##
# Represent a section by inheriting from 'defaultdict'.
class OptionDict(collections.defaultdict):
@@ -280,6 +289,7 @@ class OptionDict(collections.defaultdict):
def __setitem__(self, chunk: str, value: Entry) -> None:
super().__setitem__(chunk.lower(), value)
+
##
# Collection of all the (@a OptionDict) sections.
class SectionDict(collections.defaultdict):
@@ -313,6 +323,7 @@ class SectionDict(collections.defaultdict):
def __setitem__(self, chunk: str, value: OptionDict) -> None:
super().__setitem__(chunk.lower(), value)
+
##
# One loaded taler configuration, including base configuration
# files and included files.
@@ -323,7 +334,7 @@ class TalerConfig:
#
# @param self the object itself.
def __init__(self) -> None:
- self.sections = SectionDict() # just plain dict
+ self.sections = SectionDict() # just plain dict
##
# Load a configuration file, instantiating a config object.
@@ -465,36 +476,49 @@ class TalerConfig:
if line.startswith("@INLINE@"):
pair = line.split()
if 2 != len(pair):
- LOGGER.error("invalid inlined config filename given ('%s')" % line)
- continue
+ LOGGER.error(
+ "invalid inlined config filename given ('%s')"
+ % line)
+ continue
if pair[1].startswith("/"):
self.load_file(pair[1])
else:
- self.load_file(os.path.join(os.path.dirname(filename), pair[1]))
+ self.load_file(
+ os.path.join(os.path.dirname(filename),
+ pair[1]))
continue
if line.startswith("["):
if not line.endswith("]"):
- LOGGER.error("invalid section header in line %s: %s",
- lineno, repr(line))
+ LOGGER.error(
+ "invalid section header in line %s: %s",
+ lineno, repr(line))
section_name = line.strip("[]").strip().strip('"')
current_section = section_name
continue
if current_section is None:
- LOGGER.error("option outside of section in line %s: %s", lineno, repr(line))
+ LOGGER.error(
+ "option outside of section in line %s: %s", lineno,
+ repr(line))
continue
pair = line.split("=", 1)
if len(pair) != 2:
- LOGGER.error("invalid option in line %s: %s", lineno, repr(line))
+ LOGGER.error("invalid option in line %s: %s", lineno,
+ repr(line))
key = pair[0].strip()
value = pair[1].strip()
if value.startswith('"'):
value = value[1:]
if not value.endswith('"'):
- LOGGER.error("mismatched quotes in line %s: %s", lineno, repr(line))
+ LOGGER.error("mismatched quotes in line %s: %s",
+ lineno, repr(line))
else:
value = value[:-1]
- entry = Entry(self.sections, current_section, key,
- value=value, filename=filename, lineno=lineno)
+ entry = Entry(self.sections,
+ current_section,
+ key,
+ value=value,
+ filename=filename,
+ lineno=lineno)
sections[current_section][key] = entry
except FileNotFoundError:
# not logging here, as this interests the final user mostly.
@@ -503,23 +527,22 @@ class TalerConfig:
##
# Dump the textual representation of a config object.
- #
+ #
# Format:
- #
+ #
# [section]
# option = value # FIXME (what is location?)
#
# @param self the object itself, that will be dumped.
def dump(self) -> None:
for kv_section in self.sections.items():
- print("[%s]" % (kv_section[1].section_name,))
+ print("[%s]" % (kv_section[1].section_name, ))
for kv_option in kv_section[1].items():
print("%s = %s # %s" % \
(kv_option[1].option,
kv_option[1].value,
kv_option[1].location()))
-
##
# Return a whole section from this object.
#
@@ -538,14 +561,26 @@ if __name__ == "__main__":
import argparse
PARSER = argparse.ArgumentParser()
- PARSER.add_argument("--section", "-s", dest="section",
- default=None, metavar="SECTION")
- PARSER.add_argument("--option", "-o", dest="option",
- default=None, metavar="OPTION")
- PARSER.add_argument("--config", "-c", dest="config",
- default=None, metavar="FILE")
- PARSER.add_argument("--filename", "-f", dest="expand_filename",
- default=False, action='store_true')
+ PARSER.add_argument("--section",
+ "-s",
+ dest="section",
+ default=None,
+ metavar="SECTION")
+ PARSER.add_argument("--option",
+ "-o",
+ dest="option",
+ default=None,
+ metavar="OPTION")
+ PARSER.add_argument("--config",
+ "-c",
+ dest="config",
+ default=None,
+ metavar="FILE")
+ PARSER.add_argument("--filename",
+ "-f",
+ dest="expand_filename",
+ default=False,
+ action='store_true')
ARGS = PARSER.parse_args()
TC = TalerConfig.from_file(ARGS.config)
diff --git a/talerdonations/tests.py b/talerdonations/tests.py
index c9918c2..2e95b60 100644
--- a/talerdonations/tests.py
+++ b/talerdonations/tests.py
@@ -27,6 +27,7 @@ from talerdonations.talerconfig import TalerConfig
TC = TalerConfig.from_env()
CURRENCY = TC["taler"]["currency"].value_string(required=True)
+
##
# Main class that gathers all the tests.
class DonationsTestCase(unittest.TestCase):