Functional Weave
Code in TypeScript

auth.validate-registration@1.0.0

impl/python.py

2,060 bytes · the Python implementation · view raw

Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.

from typing import Any, Dict

from .auth_normalise_email import normalise_email  ← from auth.normalise-email ^1.0.0 · built alongside by fune
from .auth_password_policy_check_password import check_password
from .auth_password_policy_types import PasswordPolicy
from .auth_validate_registration_types import RegistrationCheck

MAX_NAME = 100
_ASCII_SPACE = " \t\n\r\f\v"


def _text(value: Any) -> str:
    # A non-string (a malformed JSON body) is an empty field, not an exception.
    return value if isinstance(value, str) else ""


def validate_registration(email: str, password: str, name: str, policy: PasswordPolicy) -> RegistrationCheck:
    """A sign-up form's email, password and name checked together: the values
    to store when valid, and a message for each field that needs fixing."""
    email_text, password_text, name_text = _text(email), _text(password), _text(name)
    fields: Dict[str, str] = {}

    normalised = normalise_email(email_text)
    if normalised is None:
        fields["email"] = (
            "Enter your email address."
            if email_text.strip(_ASCII_SPACE) == ""
            else "Enter a valid email address, like name@example.com."
        )

    trimmed_name = name_text.strip(_ASCII_SPACE)
    name_error = None
    if len(trimmed_name) == 0:
        name_error = "Enter your name."
    elif len(trimmed_name) > MAX_NAME:
        name_error = "Use no more than %d characters for your name." % MAX_NAME
    elif any(ord(ch) < 0x20 or ord(ch) == 0x7F for ch in trimmed_name):
        name_error = "Your name cannot contain control characters."

    check = check_password(password_text, normalised, trimmed_name if name_error is None else None, policy)
    if password_text == "":
        fields["password"] = "Enter a password."
    elif not check.valid:
        fields["password"] = " ".join(f.message for f in check.failures)
    if name_error is not None:
        fields["name"] = name_error

    return RegistrationCheck(
        valid=len(fields) == 0,
        email=normalised,
        name=trimmed_name if name_error is None else None,
        fields=fields,
    )