Changeset - 401cab1bcd6c
[Not reviewed]
default
0 4 0
Dennis Fink - 3 years ago 2022-08-30 10:17:27
dennis.fink@c3l.lu
Begin typing annotations
4 files changed with 19 insertions and 15 deletions:
0 comments (0 inline, 0 general)
c3l_membership/__init__.py
Show inline comments
 
import base64
 
import json
 
import os.path
 
import secrets
 
import subprocess
 
from typing import Any
 

	
 
from flask import Flask, g, redirect, request, url_for
 
from flask import Flask, Response, g, redirect, request, url_for
 
from flask.cli import AppGroup
 
from flask_babel import Babel
 
from flask_qrcode import QRcode
 

	
 
qrcode = QRcode()
 
babel = Babel()
 
babel_cli = AppGroup("babel")
 

	
 

	
 
def create_app():
 
def create_app() -> Flask:
 

	
 
    app = Flask(__name__)
 

	
 
    config_file = (
 
        os.path.abspath("config.json")
 
        if app.debug
 
        else os.path.abspath("/etc/membership.json")
 
    )
 

	
 
    try:
 
        app.config.from_file(config_file, load=json.load)
 
    except FileNotFoundError:
 
@@ -35,61 +36,61 @@ def create_app():
 
    _default_secret_key = base64.b64encode(secrets.token_bytes()).decode("utf-8")
 
    app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY", _default_secret_key)
 
    app.config["LANGUAGES"] = ["en", "de", "fr", "lb"]
 

	
 
    app.config.setdefault("SUPPORTING_FEE", 40)
 
    app.config.setdefault("REGULAR_FEE", 120)
 

	
 
    app.config.setdefault("DIGICASH_ENABLED", True)
 
    app.config.setdefault("SATISPAY_ENABLED", True)
 
    app.config.setdefault("CRYPTOCURRENCIES", dict())
 

	
 
    @babel.localeselector
 
    def get_locale():
 
    def get_locale() -> Any:
 
        if not g.get("lang_code", None):
 
            g.lang_code = request.accept_languages.best_match(app.config["LANGUAGES"])
 
        return g.lang_code
 

	
 
    from .views import root_page
 

	
 
    app.register_blueprint(root_page)
 

	
 
    @app.route("/")
 
    def home():
 
    def home() -> Response:
 
        g.lang_code = request.accept_languages.best_match(app.config["LANGUAGES"])
 
        return redirect(url_for("root.index"))
 

	
 
    app.cli.add_command(babel_cli)
 

	
 
    return app
 

	
 

	
 
@babel_cli.command("extract")
 
def babel_extract():
 
def babel_extract() -> None:
 
    subprocess.run(
 
        [
 
            "pybabel",
 
            "extract",
 
            "-F",
 
            "babel.cfg",
 
            "-k",
 
            "lazy_gettext",
 
            "-o",
 
            "messages.pot",
 
            ".",
 
        ]
 
    )
 

	
 

	
 
@babel_cli.command("update")
 
def babel_update():
 
def babel_update() -> None:
 
    subprocess.run(
 
        ["pybabel", "update", "-i", "messages.pot", "-d", "c3l_membership/translations"]
 
    )
 

	
 

	
 
@babel_cli.command("compile")
 
def babel_compile():
 
def babel_compile() -> None:
 
    subprocess.run(["pybabel", "compile", "-d", "c3l_membership/translations"])
 

	
 

	
 
app = create_app()
c3l_membership/forms.py
Show inline comments
 
from typing import Optional as tOptional
 

	
 
from flask_babel import lazy_gettext
 
from flask_wtf import FlaskForm
 
from wtforms import (
 
    BooleanField,
 
    DateField,
 
    Field,
 
    RadioField,
 
    StringField,
 
    SubmitField,
 
    ValidationError,
 
)
 
from wtforms.validators import Email, InputRequired, Length, Optional
 

	
 

	
 
class NotEqualTo:
 
    """
 
    Compares the values of two fields.
 
    :param fieldname:
 
        The name of the other field to compare to.
 
    :param message:
 
        Error message to raise in case of a validation error. Can be
 
        interpolated with `%(other_label)s` and `%(other_name)s` to provide a
 
        more helpful error.
 
    """
 

	
 
    def __init__(self, fieldname, message=None):
 
    def __init__(self, fieldname: str, message: tOptional[str] = None) -> None:
 
        self.fieldname = fieldname
 
        self.message = message
 

	
 
    def __call__(self, form, field):
 
    def __call__(self, form: FlaskForm, field: Field) -> None:
 
        try:
 
            other = form[self.fieldname]
 
        except KeyError as exc:
 
            raise ValidationError(
 
                field.gettext("Invalid field name '%s'.") % self.fieldname
 
            ) from exc
 
        if field.data != other.data:
 
            return
 

	
 
        d = {
 
            "other_label": hasattr(other, "label")
 
            and other.label.text
c3l_membership/utils.py
Show inline comments
 
from datetime import date
 

	
 

	
 
def calculate_age(birthday):
 
def calculate_age(birthday: date) -> int:
 
    today = date.today()
 
    born = birthday
 
    try:
 
        birthday = born.replace(year=today.year)
 
    except ValueError:
 
        birthday = born.replace(year=today.year, month=born.month + 1, day=1)
 

	
 
    age = today.year - born.year
 
    if birthday > today:
 
        age -= 1
 
    return age
c3l_membership/views.py
Show inline comments
 
import re
 
import subprocess
 
from datetime import date
 
from typing import Any, Dict, Optional, cast
 

	
 
import requests
 
from flask import Blueprint, current_app, g, render_template, request
 
from flask import Blueprint, Response, current_app, g, render_template, request
 
from flask_babel import gettext
 
from flask_weasyprint import HTML, render_pdf
 

	
 
from .forms import MembershipForm
 
from .utils import calculate_age
 

	
 
root_page = Blueprint("root", __name__, url_prefix="/<lang_code>")
 

	
 
xml_template = "<member><numm>{name}</numm><gebuertsdag>{birthday:%d.%m.%Y}</gebuertsdag><address>{address}</address><nick>{username}</nick><email>{email}</email><status>{status}</status><stemmrecht>{voting}</stemmrecht></member>"
 

	
 

	
 
@root_page.url_defaults
 
def add_lang_code(endpoint, values):
 
def add_lang_code(endpoint: Any, values: Dict[str, Any]) -> None:
 
    values.setdefault("lang_code", g.lang_code)
 

	
 

	
 
@root_page.url_value_preprocessor
 
def pull_lang_code(endpoint, values):
 
def pull_lang_code(endpoint: Optional[str], values: Optional[Dict[Any, Any]]) -> None:
 
    lang_code = values.pop("lang_code")
 
    if lang_code != "favicon.ico":
 
        g.lang_code = lang_code
 

	
 

	
 
@root_page.route("/", methods=("GET", "POST"))
 
def index():
 
def index() -> Response:
 
    form = MembershipForm()
 

	
 
    choices = [
 
        ("cash", gettext("by cash")),
 
        ("wire transfer", gettext("by wire transfer")),
 
    ]
 

	
 
    if current_app.config["DIGICASH_ENABLED"]:
 
        choices.append(("digicash", gettext("by DigiCash/Payconiq")))
 

	
 
    if current_app.config["SATISPAY_ENABLED"]:
 
        choices.append(("satispay", gettext("by Satispay")))
 
@@ -130,14 +131,13 @@ def index():
 
            voting=True if form.membership.data == "regular" else False,
 
            xml=xml_template.format(**xml_data),
 
            minor_member=minor_member,
 
        )
 

	
 
        if current_app.debug:
 
            return render_pdf(HTML(string=html))
 
        else:
 
            return render_pdf(
 
                HTML(string=html),
 
                download_filename=f"C3L_Membership_{form.username.data}.pdf",
 
            )
 

	
 
    return render_template("index.html", form=form, crypto_error=False)
0 comments (0 inline, 0 general)