Add support for query string params in WAGTAIL_GRAVATAR_PROVIDER_URL

- Enhance capabilities for WAGTAIL_GRAVATAR_PROVIDER_URL URL to support merging of URL params.
- Fixes #12659
- Rework of original PR #11077
pull/12681/head
Ayaan 2024-12-05 21:10:45 +05:30 zatwierdzone przez LB (Ben Johnston)
rodzic 32417f9adc
commit 3e75c018be
7 zmienionych plików z 131 dodań i 12 usunięć

Wyświetl plik

@ -14,6 +14,7 @@ Changelog
* Allow plain strings in panel definitions as shorthand for `FieldPanel` / `InlinePanel` (Matt Westcott)
* Only allow selection of valid new parents within the copy Page view (Mauro Soche)
* Add `on_serve_page` hook to modify the serving chain of pages (Krystian Magdziarz, Dawid Bugajewski)
* Add support for `WAGTAIL_GRAVATAR_PROVIDER_URL` URLs with query string parameters (Ayaan Qadri, Guilhem Saurel)
* Fix: Improve handling of translations for bulk page action confirmation messages (Matt Westcott)
* Fix: Ensure custom rich text feature icons are correctly handled when provided as a list of SVG paths (Temidayo Azeez, Joel William, LB (Ben) Johnston)
* Fix: Ensure manual edits to `StreamField` values do not throw an error (Stefan Hammer)

Wyświetl plik

@ -861,6 +861,7 @@
* Harsh Dange
* Mauro Soche
* Krystian Magdziarz
* Guilhem Saurel
## Translators

Wyświetl plik

@ -636,6 +636,14 @@ WAGTAIL_GRAVATAR_PROVIDER_URL = '//www.gravatar.com/avatar'
If a user has not uploaded a profile picture, Wagtail will look for an avatar linked to their email address on gravatar.com. This setting allows you to specify an alternative provider such as like robohash.org, or can be set to `None` to disable the use of remote avatars completely.
Any provided query string will merge with the default parameters. For example, using the setting `//www.gravatar.com/avatar?d=robohash` will use the `robohash` override instead of the default `mp` (mystery person). The `s` parameter will be ignored as this is specified depending on location within the admin interface.
See the [Gravatar images URL documentation](https://docs.gravatar.com/api/avatars/images/) for more details.
```{versionchanged} 6.4
Added query string merging.
```
(wagtail_user_time_zones)=
### `WAGTAIL_USER_TIME_ZONES`

Wyświetl plik

@ -23,6 +23,7 @@ depth: 1
* Allow plain strings in panel definitions as shorthand for `FieldPanel` / `InlinePanel` (Matt Westcott)
* Only allow selection of valid new parents within the copy Page view (Mauro Soche)
* Add [`on_serve_page`](on_serve_page) hook to modify the serving chain of pages (Krystian Magdziarz, Dawid Bugajewski)
* Add support for [`WAGTAIL_GRAVATAR_PROVIDER_URL`](wagtail_gravatar_provider_url) URLs with query string parameters (Ayaan Qadri, Guilhem Saurel)
### Bug fixes

Wyświetl plik

@ -283,7 +283,7 @@ class TestAdaptMainMenuModule(WagtailTestUtils, DjangoTestCase):
],
{
"name": user.first_name or user.get_username(),
"avatarUrl": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=100&d=mp",
"avatarUrl": "//www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?d=mp&s=100",
},
],
},

Wyświetl plik

@ -0,0 +1,76 @@
from django.test import TestCase, override_settings
from wagtail.users.utils import get_gravatar_url
class TestGravatar(TestCase):
def test_gravatar_default(self):
"""Test with the default settings"""
self.assertEqual(
get_gravatar_url("something@example.com"),
"//www.gravatar.com/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
)
def test_gravatar_custom_size(self):
"""Test with a custom size (note that the size will be doubled)"""
self.assertEqual(
get_gravatar_url("something@example.com", size=100),
"//www.gravatar.com/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=200",
)
@override_settings(
WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?d=robohash&s=200"
)
def test_gravatar_params_that_overlap(self):
"""
Test with params that overlap with default s (size) and d (default_image)
Also test the `s` is not overridden by the provider URL's query parameters.
"""
self.assertEqual(
get_gravatar_url("something@example.com", size=80),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=robohash&s=160",
)
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?f=y")
def test_gravatar_params_that_dont_overlap(self):
"""Test with params that don't default `s (size)` and `d (default_image)`"""
self.assertEqual(
get_gravatar_url("something@example.com"),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&f=y&s=100",
)
@override_settings(
WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?d=robohash&f=y"
)
def test_gravatar_query_params_override_default_params(self):
"""Test that query parameters of `WAGTAIL_GRAVATAR_PROVIDER_URL` override default_params"""
self.assertEqual(
get_gravatar_url(
"something@example.com", default_params={"d": "monsterid"}
),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=robohash&f=y&s=100",
)
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar/")
def test_gravatar_trailing_slash(self):
"""Test with a trailing slash in the URL"""
self.assertEqual(
get_gravatar_url("something@example.com"),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
)
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar")
def test_gravatar_no_trailing_slash(self):
"""Test with no trailing slash in the URL"""
self.assertEqual(
get_gravatar_url("something@example.com"),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
)
@override_settings(WAGTAIL_GRAVATAR_PROVIDER_URL="https://robohash.org/avatar?")
def test_gravatar_trailing_question_mark(self):
"""Test with a trailing question mark in the URL"""
self.assertEqual(
get_gravatar_url("something@example.com"),
"https://robohash.org/avatar/76ebd6fecabc982c205dd056e8f0415a?d=mp&s=100",
)

Wyświetl plik

@ -1,3 +1,5 @@
from urllib.parse import parse_qs, urlparse, urlunparse
from django.conf import settings
from django.utils.http import urlencode
from django.utils.translation import gettext_lazy as _
@ -25,11 +27,29 @@ def user_can_delete_user(current_user, user_to_delete):
return True
def get_gravatar_url(email, size=50):
default = "mp"
size = (
int(size) * 2
) # requested at retina size by default and scaled down at point of use with css
def get_gravatar_url(email, size=50, default_params={"d": "mp"}):
"""
See https://gravatar.com/site/implement/images/ for Gravatar image options.
Example usage:
.. 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"
)
@ -37,14 +57,26 @@ def get_gravatar_url(email, size=50):
if (not email) or (gravatar_provider_url is None):
return None
email_bytes = email.lower().encode("utf-8")
hash = safe_md5(email_bytes, usedforsecurity=False).hexdigest()
gravatar_url = "{gravatar_provider_url}/{hash}?{params}".format(
gravatar_provider_url=gravatar_provider_url.rstrip("/"),
hash=hash,
params=urlencode({"s": size, "d": default}),
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