Repository: wagtail/wagtail
File: wagtail/users/utils.py (Python)

Code before:
        "s": int(size)
        * 2,  # requested at retina size by default and scaled down at point of use with css
        "d": DEFAULT_IMAGE,
    }

    gravatar_provider_url = getattr(
        settings, "WAGTAIL_GRAVATAR_PROVIDER_URL", DEFAULT_GRAVATAR_PROVIDER_URL
    )

    if (not email) or (gravatar_provider_url is None):
        return None

    parsed_url = urlparse(gravatar_provider_url.rstrip("/"))

    if parsed_url.query:
        params.update(
            **{key: value[-1] for key, value in parse_qs(parsed_url.query).items()},
        )
    params.update(**default_params)

    email_hash = safe_md5(
        email.lower().encode("utf-8"), usedforsecurity=False
    ).hexdigest()

    gravatar_url = (
        f"//{parsed_url.netloc}{parsed_url.path}/{email_hash}?{urlencode(params)}"
    )

    return gravatar_url


def get_deleted_user_display_name(user_id):
    # Use a string placeholder as the user id could be non-numeric
    return _("user %(id)s (deleted)") % {"id": user_id}


Review comment (refactor):
```suggestion
        f"//{parsed_url.netloc}{parsed_url.path}/{email_hash}?{urlencode(params, doseq=True)}"
```

This should encode the URL params back to duplicate values instead of formatting an array.
https://docs.djangoproject.com/en/5.0/ref/utils/#django.utils.http.urlencode

This is based on the Python urlencode which has the same kwarg
https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode

Also, I would recommend instead of building up the URL manually like this, you try to use the urljoin function.

https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urljoin

or maybe `unsplit`.


Code after:

    .. code-block:: python

        # Basic usage
        gravatar_url = get_gravatar_url('user@example.com')

        # Customize size and default image
        gravatar_url = get_gravatar_url(
            'user@example.com',
            size=100,
            default_params={'d': 'robohash', 'f': 'y'}
        )

    Note:
        If any parameter in ``default_params`` also exists in the provider URL,
        it will be overridden by the provider URL's query parameter.
    """

    gravatar_provider_url = getattr(
        settings, "WAGTAIL_GRAVATAR_PROVIDER_URL", "//www.gravatar.com/avatar"
    )

    if (not email) or (gravatar_provider_url is None):
        return None

    parsed_url = urlparse(gravatar_provider_url)

    params = {
        **default_params,
        **(parse_qs(parsed_url.query or "")),
        # requested at retina size by default and scaled down at point of use with css
        "s": int(size) * 2,
    }

    email_hash = safe_md5(
        email.lower().encode("utf-8"), usedforsecurity=False
    ).hexdigest()

    parsed_url = parsed_url._replace(
        path=f"{parsed_url.path.rstrip('/')}/{email_hash}",
        query=urlencode(params, doseq=True),
    )

    gravatar_url = urlunparse(parsed_url)

    return gravatar_url


def get_deleted_user_display_name(user_id):
    # Use a string placeholder as the user id could be non-numeric
    return _("user %(id)s (deleted)") % {"id": user_id}