diff --git a/INSTALL.md b/INSTALL.md index 37bda58..837a5d9 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -63,7 +63,35 @@ pip install -r requirements.txt ./manage.py test -v3 # Or any other verbosity level you like ``` -## OpenID Connect authentication with Fedora +## Configuration + +### Gravatar Proxy and Redirect Settings + +By default, ivatar is configured to work well for public instances like libravatar.org. However, for local or private instances, you may want to disable external requests to Gravatar. You can configure the default behavior by adding these settings to your `config_local.py`: + +```python +# Default settings for Gravatar proxy and redirect behavior +# These can be overridden by URL parameters (?gravatarproxy=n&gravatarredirect=n) + +# Whether to proxy requests to Gravatar when no local avatar is found (default: True) +DEFAULT_GRAVATARPROXY = False + +# Whether to redirect directly to Gravatar when no local avatar is found (default: False) +DEFAULT_GRAVATARREDIRECT = False + +# Whether to force default behavior even when a user avatar exists (default: False) +FORCEDEFAULT = False +``` + +**Use cases:** + +- **Private/Local instances**: Set `DEFAULT_GRAVATARPROXY = False` and `DEFAULT_GRAVATARREDIRECT = False` to prevent external requests +- **Gravatar-first instances**: Set `DEFAULT_GRAVATARREDIRECT = True` to redirect to Gravatar instead of proxying +- **Testing/Development**: Set `FORCEDEFAULT = True` to always use default avatars + +**Note**: URL parameters (`?gravatarproxy=n`, `?gravatarredirect=y`, `?forcedefault=y`) will always override these configuration defaults. + +### OpenID Connect authentication with Fedora To enable OpenID Connect (OIDC) authentication with Fedora, you must have obtained a `client_id` and `client_secret` pair from the Fedora Infrastructure. Then you must set these values in `config_local.py`: diff --git a/config.py b/config.py index 4070f48..6f60bd8 100644 --- a/config.py +++ b/config.py @@ -196,6 +196,12 @@ ALLOWED_EXTERNAL_OPENID_REDIRECT_DOMAINS = [ DEFAULT_AVATAR_SIZE = 80 +# Default settings for Gravatar proxy and redirect behavior +# These can be overridden by URL parameters +DEFAULT_GRAVATARPROXY = True +DEFAULT_GRAVATARREDIRECT = False +FORCEDEFAULT = False + LANGUAGES = ( ("de", _("Deutsch")), ("en", _("English")), diff --git a/config_local.py.example b/config_local.py.example index 5b77766..c3c4467 100644 --- a/config_local.py.example +++ b/config_local.py.example @@ -48,3 +48,18 @@ import os # Bluesky integration credentials # BLUESKY_IDENTIFIER = "your-bluesky-handle" # BLUESKY_APP_PASSWORD = "your-app-password" + +# Gravatar proxy and redirect settings +# These control the default behavior when no local avatar is found +# URL parameters (?gravatarproxy=n&gravatarredirect=y) will override these defaults + +# For private/local instances that should not make external requests: +# DEFAULT_GRAVATARPROXY = False +# DEFAULT_GRAVATARREDIRECT = False + +# For instances that prefer direct Gravatar redirects: +# DEFAULT_GRAVATARREDIRECT = True +# DEFAULT_GRAVATARPROXY = False + +# For testing/development (always use default avatars): +# FORCEDEFAULT = True diff --git a/ivatar/test_config_defaults.py b/ivatar/test_config_defaults.py new file mode 100644 index 0000000..f018730 --- /dev/null +++ b/ivatar/test_config_defaults.py @@ -0,0 +1,90 @@ +""" +Unit tests for configurable default settings +""" + +import unittest +from unittest.mock import patch +import os +import django + +os.environ["DJANGO_SETTINGS_MODULE"] = "ivatar.settings" +django.setup() + +from django.test import TestCase + + +class ConfigurableDefaultsTestCase(TestCase): + """ + Test cases for configurable default settings for gravatarproxy, gravatarredirect, and forcedefault + """ + + def test_config_imports_successfully(self): + """ + Test that the new configuration options can be imported successfully + """ + try: + from ivatar.settings import ( + DEFAULT_GRAVATARPROXY, + DEFAULT_GRAVATARREDIRECT, + FORCEDEFAULT, + ) + + # Test that they have the expected default values + self.assertTrue(isinstance(DEFAULT_GRAVATARPROXY, bool)) + self.assertTrue(isinstance(DEFAULT_GRAVATARREDIRECT, bool)) + self.assertTrue(isinstance(FORCEDEFAULT, bool)) + except ImportError as e: + self.fail(f"Failed to import configuration settings: {e}") + + def test_views_imports_config_successfully(self): + """ + Test that views.py can import the new configuration options + """ + try: + from ivatar.views import ( + DEFAULT_GRAVATARPROXY, + DEFAULT_GRAVATARREDIRECT, + FORCEDEFAULT, + ) + + # Test that they have the expected default values + self.assertTrue(isinstance(DEFAULT_GRAVATARPROXY, bool)) + self.assertTrue(isinstance(DEFAULT_GRAVATARREDIRECT, bool)) + self.assertTrue(isinstance(FORCEDEFAULT, bool)) + except ImportError as e: + self.fail(f"Failed to import configuration settings in views: {e}") + + @patch("ivatar.settings.DEFAULT_GRAVATARPROXY", False) + @patch("ivatar.settings.DEFAULT_GRAVATARREDIRECT", True) + @patch("ivatar.settings.FORCEDEFAULT", True) + def test_config_values_can_be_overridden(self): + """ + Test that configuration values can be overridden (mocked for testing) + """ + from ivatar import settings + + # These should reflect the patched values + self.assertFalse(settings.DEFAULT_GRAVATARPROXY) + self.assertTrue(settings.DEFAULT_GRAVATARREDIRECT) + self.assertTrue(settings.FORCEDEFAULT) + + def test_default_values_are_correct(self): + """ + Test that the default values match the issue requirements + """ + from ivatar.settings import ( + DEFAULT_GRAVATARPROXY, + DEFAULT_GRAVATARREDIRECT, + FORCEDEFAULT, + ) + + # Based on the issue, these should be the defaults for public instances + self.assertTrue( + DEFAULT_GRAVATARPROXY + ) # Default should be True for public instances + self.assertFalse(DEFAULT_GRAVATARREDIRECT) # Default should be False + self.assertFalse(FORCEDEFAULT) # Default should be False + + +if __name__ == "__main__": + unittest.main() diff --git a/ivatar/views.py b/ivatar/views.py index 5237402..b7f0eca 100644 --- a/ivatar/views.py +++ b/ivatar/views.py @@ -33,6 +33,11 @@ from ivatar.settings import AVATAR_MAX_SIZE, JPEG_QUALITY, DEFAULT_AVATAR_SIZE from ivatar.settings import CACHE_RESPONSE from ivatar.settings import CACHE_IMAGES_MAX_AGE from ivatar.settings import TRUSTED_DEFAULT_URLS +from ivatar.settings import ( + DEFAULT_GRAVATARPROXY, + DEFAULT_GRAVATARREDIRECT, + FORCEDEFAULT, +) from .ivataraccount.models import ConfirmedEmail, ConfirmedOpenId from .ivataraccount.models import UnconfirmedEmail, UnconfirmedOpenId from .ivataraccount.models import Photo @@ -144,9 +149,9 @@ class AvatarImageView(TemplateView): imgformat = "png" obj = None default = None - forcedefault = False - gravatarredirect = False - gravatarproxy = True + forcedefault = FORCEDEFAULT + gravatarredirect = DEFAULT_GRAVATARREDIRECT + gravatarproxy = DEFAULT_GRAVATARPROXY uri = request.build_absolute_uri() # Check the cache first