debianmemberportfolio/debianmemberportfolio/model/urlbuilder.py
Jan Dittberner 29b05952d7 Fix bugs reported by Paul Wise
- fix internal server error when name is missing for non Debian member
- fix unicode handling in urlbuilder
2023-06-03 17:56:08 +02:00

142 lines
5 KiB
Python

# -*- python -*-
# -*- coding: utf8 -*-
#
# Debian Member Portfolio Service url builder
#
# Copyright © 2009-2023 Jan Dittberner <jan@dittberner.info>
#
# This file is part of the Debian Member Portfolio Service.
#
# Debian Member Portfolio Service is free software: you can redistribute it
# and/or modify it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the License,
# or (at your option) any later version.
#
# Debian Member Portfolio Service 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 Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
"""
This module provides the function build_urls to build personalized
URLs using the given information and the URL patterns defined in
portfolio.ini.
"""
from configparser import ConfigParser, InterpolationMissingOptionError
from encodings.utf_8 import StreamReader as UTF8StreamReader
from importlib import resources
from urllib.parse import quote_plus
from debianmemberportfolio.model import keyfinder
from flask_babel import gettext as _
from flask_babel import lazy_gettext as N_
my_config = ConfigParser()
ref = resources.files("debianmemberportfolio.model").joinpath("portfolio.ini")
with ref.open("rb") as fp:
my_config.read_file(UTF8StreamReader(fp))
_FIELDNAMES_MAP = {
"email": N_("Email address"),
"name": N_("Name"),
"openpgpfp": N_("OpenPGP fingerprint"),
"username": N_("Debian user name"),
"nonddemail": N_("Non Debian email address"),
"salsausername": N_("Salsa user name"),
}
class DDPortfolioEntry(object):
def __init__(self, config, section, key):
self.name = key
self.optional = (
config.has_option(section, key + ".optional")
and config.getboolean(section, key + ".optional")
or False
)
if config.has_option(section, key + ".type"):
self.type = config.get(section, key + ".type")
else:
self.type = "url"
def _build_quoted_fields(fields):
"""
Take a dictionary of raw field values and quote the values if required.
"""
qfields = {}
for key, value in fields.items():
if value is not None:
if isinstance(value, str):
qfields[key] = quote_plus(value.encode("utf8"))
elif isinstance(value, str):
qfields[key] = quote_plus(value)
else:
qfields[key] = value
qfields[key] = str(qfields[key]).replace("%", "%%")
if "openpgpfp" not in qfields:
fpr = keyfinder.getFingerprintByEmail(fields["email"])
if fpr:
qfields["openpgpfp"] = fpr[0]
qfields["firstchar"] = fields["email"][0]
qfields["emailnoq"] = fields["email"]
return qfields
def build_urls(fields):
"""Build personalized URLs using the developer information in
fields."""
data = []
quoted_fields = _build_quoted_fields(fields)
for section in [
section.strip()
for section in my_config.get("DEFAULT", "urlbuilder.sections").split(",")
]:
data.append(["section", section])
if my_config.has_option(section, "urls"):
for entry in [
DDPortfolioEntry(my_config, section, url)
for url in my_config.get(section, "urls").split(",")
]:
try:
data.append(
[
"url",
section,
entry,
my_config.get(
section,
entry.name + ".pattern",
raw=False,
vars=quoted_fields,
),
]
)
except InterpolationMissingOptionError as e:
if not entry.optional:
if e.reference in _FIELDNAMES_MAP:
data.append(
[
"error",
section,
entry,
_("Missing input: %s")
% _(_FIELDNAMES_MAP[e.reference]),
]
)
else:
data.append(
[
"error",
section,
entry,
_("Missing input: %s") % e.reference,
]
)
return data