summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Dold <florian.dold@gmail.com>2019-08-29 21:40:26 +0200
committerFlorian Dold <florian.dold@gmail.com>2019-08-29 21:40:26 +0200
commit26f544d308ba5328352904617c7d0994461e4758 (patch)
treed5f0b88dcd6de4f937b21a135841590b1f771cff
parent42dcfa19000aa2f02e94cc9b4c1c99c667a539ab (diff)
downloadbackoffice-26f544d308ba5328352904617c7d0994461e4758.tar.gz
backoffice-26f544d308ba5328352904617c7d0994461e4758.tar.bz2
backoffice-26f544d308ba5328352904617c7d0994461e4758.zip
make pretty
-rw-r--r--talerbackoffice/backoffice/backoffice.py46
-rwxr-xr-xtalerbackoffice/backoffice/templates/template.py54
-rw-r--r--talerbackoffice/helpers.py26
-rw-r--r--talerbackoffice/talerconfig.py94
-rw-r--r--talerbackoffice/tests.py17
5 files changed, 150 insertions, 87 deletions
diff --git a/talerbackoffice/backoffice/backoffice.py b/talerbackoffice/backoffice/backoffice.py
index 8b6242b..ef74dd9 100644
--- a/talerbackoffice/backoffice/backoffice.py
+++ b/talerbackoffice/backoffice/backoffice.py
@@ -17,8 +17,6 @@
#
# @author Florian Dold
# @author Marcello Stanisci
-
-
"""
Implement URL handlers for backoffice logic.
"""
@@ -61,19 +59,23 @@ LANGUAGES = {
'ru': 'Russian',
}
+
@babel.localeselector
def get_locale():
- # If any "lang" component exists in the path, then
- # it must be at the second position into the split array.
- lang = flask.request.path.split("/")[1]
- return lang if lang in LANGUAGES.keys() else "en"
+ # If any "lang" component exists in the path, then
+ # it must be at the second position into the split array.
+ lang = flask.request.path.split("/")[1]
+ return lang if lang in LANGUAGES.keys() else "en"
+
@app.context_processor
def utility_processor():
def url(my_url):
return join_urlparts(flask.request.script_root, my_url)
+
def env(name, default=None):
return os.environ.get(name, default)
+
return dict(url=url, env=env)
@@ -81,7 +83,10 @@ def utility_processor():
@app.route("/", defaults={"lang": "en"})
def index(lang):
# 'lang' parameter not used.
- return flask.render_template("templates/backoffice.html", instances=INSTANCES.split())
+ return flask.render_template(
+ "templates/backoffice.html", instances=INSTANCES.split()
+ )
+
@app.route("/javascript")
def javascript_licensing():
@@ -92,10 +97,11 @@ def javascript_licensing():
def history():
qs = get_query_string().decode("utf-8")
url = urljoin(BACKEND_URL, "history")
- resp = requests.get(url,
- params=dict(parse_qsl(qs)),
- headers={"Authorization":
- "ApiKey sandbox"})
+ resp = requests.get(
+ url,
+ params=dict(parse_qsl(qs)),
+ headers={"Authorization": "ApiKey sandbox"}
+ )
if resp.status_code != 200:
return backend_error(resp)
return flask.jsonify(resp.json()), resp.status_code
@@ -105,10 +111,11 @@ def history():
def track_transfer():
qs = get_query_string().decode("utf-8")
url = urljoin(BACKEND_URL, "track/transfer")
- resp = requests.get (url,
- params=dict(parse_qsl(qs)),
- headers={"Authorization":
- "ApiKey sandbox"})
+ resp = requests.get(
+ url,
+ params=dict(parse_qsl(qs)),
+ headers={"Authorization": "ApiKey sandbox"}
+ )
if resp.status_code != 200:
return backend_error(resp)
return flask.jsonify(resp.json()), resp.status_code
@@ -118,10 +125,11 @@ def track_transfer():
def track_order():
qs = get_query_string().decode("utf-8")
url = urljoin(BACKEND_URL, "track/transaction")
- resp = requests.get(url,
- params=dict(parse_qsl(qs)),
- headers={"Authorization":
- "ApiKey sandbox"})
+ resp = requests.get(
+ url,
+ params=dict(parse_qsl(qs)),
+ headers={"Authorization": "ApiKey sandbox"}
+ )
if resp.status_code != 200:
return backend_error(resp)
return flask.jsonify(resp.json()), resp.status_code
diff --git a/talerbackoffice/backoffice/templates/template.py b/talerbackoffice/backoffice/templates/template.py
index eae04eb..aad9cf7 100755
--- a/talerbackoffice/backoffice/templates/template.py
+++ b/talerbackoffice/backoffice/templates/template.py
@@ -19,20 +19,24 @@ import os
sys.path.append(os.getcwd())
import i18nfix
-env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
- extensions=["jinja2.ext.i18n"],
- lstrip_blocks=True,
- trim_blocks=True,
- undefined=jinja2.StrictUndefined,
- autoescape=False)
+env = jinja2.Environment(
+ loader=jinja2.FileSystemLoader(os.path.dirname(__file__)),
+ extensions=["jinja2.ext.i18n"],
+ lstrip_blocks=True,
+ trim_blocks=True,
+ undefined=jinja2.StrictUndefined,
+ autoescape=False
+)
-langs_full = {"en": "English",
- "fr": "Français",
- "it": "Italiano",
- "es": "Español",
- "de": "Deutsch",
- "ru": "Ру́сский язы́к",
- "pt": "Português"}
+langs_full = {
+ "en": "English",
+ "fr": "Français",
+ "it": "Italiano",
+ "es": "Español",
+ "de": "Deutsch",
+ "ru": "Ру́сский язы́к",
+ "pt": "Português"
+}
for in_file in glob.glob("*.j2"):
name, ext = re.match(r"(.*)\.([^.]+)$", in_file.rstrip(".j2")).groups()
@@ -49,7 +53,7 @@ for in_file in glob.glob("*.j2"):
def svg_localized(filename):
lf = filename + "." + locale + ".svg"
- if "en" == locale or not os.path.isfile (lf):
+ if "en" == locale or not os.path.isfile(lf):
return "../" + filename + ".svg"
else:
return "../" + lf
@@ -62,23 +66,23 @@ for in_file in glob.glob("*.j2"):
for l in glob.glob("locale/*/"):
locale = os.path.basename(l[:-1])
- tr = gettext.translation("messages",
- localedir="locale",
- languages=[locale])
+ tr = gettext.translation(
+ "messages", localedir="locale", languages=[locale]
+ )
tr.gettext = i18nfix.wrap_gettext(tr.gettext)
env.install_gettext_translations(tr, newstyle=True)
-
content = tmpl.render(
- lang=locale,
- lang_full=langs_full[locale],
- url=url,
- self_localized=self_localized,
- url_localized=url_localized,
- svg_localized=svg_localized,
- filename=name + "." + ext)
+ lang=locale,
+ lang_full=langs_full[locale],
+ url=url,
+ self_localized=self_localized,
+ url_localized=url_localized,
+ svg_localized=svg_localized,
+ filename=name + "." + ext
+ )
out_name = "./" + locale + "/" + in_file.rstrip(".j2")
os.makedirs("./" + locale, exist_ok=True)
with codecs.open(out_name, "w", "utf-8") as f:
diff --git a/talerbackoffice/helpers.py b/talerbackoffice/helpers.py
index d574126..46e4fdd 100644
--- a/talerbackoffice/helpers.py
+++ b/talerbackoffice/helpers.py
@@ -33,11 +33,13 @@ FRACTION_BASE = 1e8
if not NDIGITS:
NDIGITS = 2
+
class MissingParameterException(Exception):
def __init__(self, param):
self.param = param
super().__init__()
+
def amount_to_float(amount):
return amount['value'] + (float(amount['fraction']) / float(FRACTION_BASE))
@@ -82,7 +84,9 @@ def make_url(page, *query_params):
def expect_parameter(name, alt=None):
value = flask.request.args.get(name, None)
if value is None and alt is None:
- LOGGER.error("Missing parameter '%s' from '%s'." % (name, flask.request.args))
+ LOGGER.error(
+ "Missing parameter '%s' from '%s'." % (name, flask.request.args)
+ )
raise MissingParameterException(name)
return value if value else alt
@@ -90,12 +94,20 @@ def expect_parameter(name, alt=None):
def get_query_string():
return flask.request.query_string
+
def backend_error(requests_response):
- LOGGER.error("Backend error: status code: "
- + str(requests_response.status_code))
+ LOGGER.error(
+ "Backend error: status code: " + str(requests_response.status_code)
+ )
try:
- return flask.jsonify(requests_response.json()), requests_response.status_code
+ 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
+ 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
diff --git a/talerbackoffice/talerconfig.py b/talerbackoffice/talerconfig.py
index 4a4b2d1..5c9f300 100644
--- a/talerbackoffice/talerconfig.py
+++ b/talerbackoffice/talerconfig.py
@@ -13,7 +13,6 @@
# TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
#
# @author Florian Dold
-
"""
Parse GNUnet-style configurations in pure Python
"""
@@ -37,9 +36,11 @@ try:
except ImportError:
pass
+
class ConfigurationError(Exception):
pass
+
class ExpansionSyntaxError(Exception):
pass
@@ -66,7 +67,7 @@ def expand(var, getter):
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)
@@ -79,16 +80,15 @@ def expand(var, getter):
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]
result = result + replace
pos = end
-
return result + var[pos:]
@@ -97,12 +97,15 @@ class OptionDict(collections.defaultdict):
self.config = weakref.ref(config)
self.section_name = section_name
super().__init__()
+
def __missing__(self, key):
entry = Entry(self.config(), self.section_name, key)
self[key] = entry
return entry
+
def __getitem__(self, chunk):
return super().__getitem__(chunk.lower())
+
def __setitem__(self, chunk, value):
super().__setitem__(chunk.lower(), value)
@@ -112,8 +115,10 @@ class SectionDict(collections.defaultdict):
value = OptionDict(self, key)
self[key] = value
return value
+
def __getitem__(self, chunk):
return super().__getitem__(chunk.lower())
+
def __setitem__(self, chunk, value):
super().__setitem__(chunk.lower(), value)
@@ -141,11 +146,16 @@ 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
@@ -210,15 +220,18 @@ class TalerConfig:
def value_string(self, section, option, **kwargs):
return self.sections[section][option].value_string(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
def value_filename(self, section, option, **kwargs):
return self.sections[section][option].value_filename(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
def value_int(self, section, option, **kwargs):
return self.sections[section][option].value_int(
- kwargs.get("default"), kwargs.get("required"), kwargs.get("warn"))
+ kwargs.get("default"), kwargs.get("required"), kwargs.get("warn")
+ )
def load_defaults(self):
base_dir = os.environ.get("TALER_BASE_CONFIG")
@@ -274,36 +287,51 @@ class TalerConfig:
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:
LOGGER.error("Configuration file (%s) not found", filename)
sys.exit(3)
-
def dump(self):
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,
@@ -320,14 +348,22 @@ 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/talerbackoffice/tests.py b/talerbackoffice/tests.py
index d7b3949..a03ae3c 100644
--- a/talerbackoffice/tests.py
+++ b/talerbackoffice/tests.py
@@ -9,21 +9,21 @@ from bs4 import BeautifulSoup
TC = TalerConfig.from_env()
CURRENCY = TC["taler"]["currency"].value_string(required=True)
+
class BackofficeTestCase(unittest.TestCase):
def setUp(self):
backoffice.app.testing = True
self.app = backoffice.app.test_client()
+
# Check whether the homepage UI shows the instances
# in the drop-down menu. Instances are read from the
# environment.
def test_instances_are_shown(self):
response = self.app.get("/")
soup = BeautifulSoup(response.data, "html.parser")
- self.assertEqual("MusicShop",
- soup.find("select").option.contents[0])
+ self.assertEqual("MusicShop", soup.find("select").option.contents[0])
self.assertEqual(response.status_code, 200)
-
@patch("requests.get")
def test_track_order(self, mocked_get):
ret = MagicMock()
@@ -34,7 +34,8 @@ class BackofficeTestCase(unittest.TestCase):
mocked_get.assert_called_with(
"http://backend.example.com/track/transaction",
params=dict(para1='1', para2='2'),
- headers={"Authorization": "ApiKey sandbox"})
+ headers={"Authorization": "ApiKey sandbox"}
+ )
# check data is returned verbatim from the backend
self.assertEqual(response.data, b'{}\n')
@@ -48,11 +49,11 @@ class BackofficeTestCase(unittest.TestCase):
mocked_get.assert_called_with(
"http://backend.example.com/track/transfer",
params=dict(para1='1', para2='2'),
- headers={"Authorization": "ApiKey sandbox"})
+ headers={"Authorization": "ApiKey sandbox"}
+ )
# check data is returned verbatim from the backend
self.assertEqual(response.data, b'{}\n')
-
@patch("requests.get")
def test_history(self, mocked_get):
ret = MagicMock()
@@ -63,7 +64,8 @@ class BackofficeTestCase(unittest.TestCase):
mocked_get.assert_called_with(
"http://backend.example.com/history",
params=dict(para1='1', para2='2'),
- headers={"Authorization": "ApiKey sandbox"})
+ headers={"Authorization": "ApiKey sandbox"}
+ )
self.assertEqual(response.data, b'{}\n')
def test_javascript_license_page(self):
@@ -71,5 +73,6 @@ class BackofficeTestCase(unittest.TestCase):
soup = BeautifulSoup(response.data, "html.parser")
self.assertEqual(soup.body.table["id"], "jslicense-labels1")
+
if __name__ == "__main__":
unittest.main()