# -*- python -*- # -*- coding: utf8 -*- # # Debian Member Portfolio Service url builder # # Copyright © 2009-2023 Jan Dittberner # # 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 . # """ 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