-
Notifications
You must be signed in to change notification settings - Fork 54
Feat: add Terms of Use accept view and middleware #1217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
1deac58
feat(accounts,ToU): add ToU update view, form and middleware #141 #161
MyPyDavid 187c630
tests(accounts,ToU): add tests for ToU update and middleware
MyPyDavid 8c2a84b
refactor(accounts, middleware): change ToU middleware to callable class
MyPyDavid 3c2a3bc
feat(accounts,ToU): add updated and created to Consent Model
MyPyDavid 0d694f7
feat(accounts,admin): update list display for ConsentFieldValue
MyPyDavid e52f940
feat(accounts,ToU): disable revocation and rename to accept
MyPyDavid 22b63d4
feat(accounts,ToU): add version date check, refactor and fix tests
MyPyDavid fa8b7d1
refactor(core,accounts): move ToU settings and date parser to core an…
MyPyDavid c510027
feat(sociallaccount): add ToU to social signup form
MyPyDavid 1512135
tests(accounts): fix helpers and code style
MyPyDavid e86843c
tests(accounts): add allauth.socialaccount to base config and fix soc…
MyPyDavid f2c4ffb
tests(accounts): fix import and code style
MyPyDavid 3aa760a
refactor(core): rename to CoreConfig and remove ready method
MyPyDavid ead1f71
refactor(core,ToU): add ToU middleware to MIDDLEWARE by default
MyPyDavid 28ecef0
fix(core,utils): use input date arg
MyPyDavid 356f92e
tests(core,utils): add tests for the date parser
MyPyDavid b9cdafc
refactor(accounts): rename adapter.py to account.py
MyPyDavid File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| """Terms and Conditions Middleware""" | ||
| # ref: https://github.com/cyface/django-termsandconditions/blob/main/termsandconditions/middleware.py | ||
|
|
||
| from django.conf import settings | ||
| from django.http import HttpResponseRedirect | ||
| from django.urls import reverse | ||
|
|
||
| from .models import ConsentFieldValue | ||
|
|
||
|
|
||
| class TermsAndConditionsRedirectMiddleware: | ||
| """Middleware to ensure terms and conditions have been accepted.""" | ||
|
|
||
| def __init__(self, get_response): | ||
| self.get_response = get_response | ||
|
|
||
| def __call__(self, request): | ||
| if ( | ||
| settings.ACCOUNT_TERMS_OF_USE # Terms enforcement enabled | ||
| and request.user.is_authenticated | ||
| and self.is_path_protected(request.path) | ||
| and not ConsentFieldValue.has_accepted_terms(request.user, request.session) | ||
| ): | ||
| return HttpResponseRedirect(reverse("terms_of_use_accept")) | ||
|
|
||
| # Proceed with the response for non-protected paths or accepted terms | ||
| return self.get_response(request) | ||
|
|
||
| @staticmethod | ||
| def is_path_protected(path): | ||
| # all paths should be protected, except what is excluded here | ||
| return not ( | ||
| path == reverse("terms_of_use_accept") or | ||
| any(path.startswith(prefix) for prefix in settings.ACCOUNT_TERMS_OF_USE_EXCLUDE_URL_PREFIXES) or | ||
| any(substring in path for substring in settings.ACCOUNT_TERMS_OF_USE_EXCLUDE_URL_CONTAINS) or | ||
| path in settings.ACCOUNT_TERMS_OF_USE_EXCLUDE_URLS | ||
| ) |
26 changes: 26 additions & 0 deletions
26
rdmo/accounts/migrations/0022_add_created_updated_to_consent.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Generated by Django 4.2.17 on 2025-01-23 16:06 | ||
|
|
||
| from django.db import migrations, models | ||
| import django.utils.timezone | ||
|
|
||
|
|
||
| class Migration(migrations.Migration): | ||
|
|
||
| dependencies = [ | ||
| ('accounts', '0021_alter_help_text'), | ||
| ] | ||
|
|
||
| operations = [ | ||
| migrations.AddField( | ||
| model_name='consentfieldvalue', | ||
| name='created', | ||
| field=models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='created'), | ||
| preserve_default=False, | ||
| ), | ||
| migrations.AddField( | ||
| model_name='consentfieldvalue', | ||
| name='updated', | ||
| field=models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='updated'), | ||
| preserve_default=False, | ||
| ), | ||
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| from django.conf import settings | ||
MyPyDavid marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| from django.contrib.auth.models import Group | ||
| from django.forms import BooleanField | ||
|
|
||
| from allauth.socialaccount.adapter import DefaultSocialAccountAdapter | ||
| from allauth.socialaccount.forms import SignupForm as AllauthSocialSignupForm | ||
|
|
||
| from rdmo.accounts.forms import ProfileForm | ||
| from rdmo.accounts.models import ConsentFieldValue | ||
|
|
||
|
|
||
| class SocialAccountAdapter(DefaultSocialAccountAdapter): | ||
|
|
||
| def is_open_for_signup(self, request, sociallogin): | ||
| return settings.SOCIALACCOUNT_SIGNUP | ||
|
|
||
| def save_user(self, request, sociallogin, form=None): | ||
| user = super().save_user(request, sociallogin, form) | ||
|
|
||
| if settings.SOCIALACCOUNT_GROUPS: | ||
| provider = str(sociallogin.account.provider) | ||
| groups = Group.objects.filter(name__in=settings.SOCIALACCOUNT_GROUPS.get(provider, [])) | ||
| user.groups.set(groups) | ||
|
|
||
| return user | ||
|
|
||
|
|
||
| class SocialSignupForm(AllauthSocialSignupForm, ProfileForm): | ||
jochenklar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| use_required_attribute = False | ||
|
|
||
| def __init__(self, *args, **kwargs): | ||
| super().__init__(*args, **kwargs) | ||
|
|
||
| # add a consent field, the label is added in the template | ||
| if settings.ACCOUNT_TERMS_OF_USE: | ||
| self.fields['consent'] = BooleanField(required=True) | ||
|
|
||
| def signup(self, request, user): | ||
| self._save_additional_values(user) | ||
|
|
||
| # store the consent field | ||
| if settings.ACCOUNT_TERMS_OF_USE: | ||
| if self.cleaned_data['consent']: | ||
| ConsentFieldValue.create_consent(user=user, session=request.session) | ||
46 changes: 46 additions & 0 deletions
46
rdmo/accounts/templates/account/terms_of_use_accept_form.html
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| {% extends 'core/page.html' %} | ||
| {% load i18n %} | ||
|
|
||
| {% block page %} | ||
|
|
||
| <h2>{% trans 'Terms of use' %}</h2> | ||
|
|
||
| <p> | ||
| {% get_current_language as lang %} | ||
| {% if lang == 'en' %} | ||
| {% include 'account/terms_of_use_en.html' %} | ||
| {% elif lang == 'de' %} | ||
| {% include 'account/terms_of_use_de.html' %} | ||
| {% endif %} | ||
| </p> | ||
|
|
||
| <div> | ||
| {% if not has_consented %} | ||
| <form method="post"> | ||
| {% csrf_token %} | ||
| <div class="form-group"> | ||
| <label> | ||
| <input type="checkbox" name="consent" required> | ||
| {% trans "I agree to the terms of use." %} | ||
| </label> | ||
| </div> | ||
| <button type="submit" class="btn btn-primary terms-of-use-accept"> | ||
| {% trans "I accept" %} | ||
| </button> | ||
| </form> | ||
| {% else %} | ||
| <p> | ||
| {% trans "You have accepted the terms of use." %} | ||
| </p> | ||
| {% endif %} | ||
|
|
||
| {% if form.non_field_errors %} | ||
| <ul class="list-unstyled text-danger"> | ||
| {% for error in form.non_field_errors %} | ||
| <li>{{ error }}</li> | ||
| {% endfor %} | ||
| </ul> | ||
| {% endif %} | ||
| </div> | ||
|
|
||
| {% endblock %} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,64 @@ | ||
| import sys | ||
| from importlib import import_module, reload | ||
|
|
||
| import pytest | ||
|
|
||
| from django.urls import clear_url_caches, get_resolver, reverse | ||
|
|
||
|
|
||
| def reload_urlconf(urlconf=None, root_urlconf=None): | ||
jochenklar marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| clear_url_caches() | ||
| if urlconf is None and root_urlconf is None: | ||
| from django.conf import settings | ||
| urlconf = settings.ROOT_URLCONF | ||
| elif urlconf is None and root_urlconf is not None: | ||
| # take the settings during pytest run | ||
| urlconf = root_urlconf | ||
|
|
||
| if urlconf in sys.modules: | ||
| reload(sys.modules[urlconf]) | ||
| else: | ||
| import_module(urlconf) | ||
|
|
||
|
|
||
| def reload_urls(*app_names: str, root_urlconf = None) -> None: | ||
| # reload the urlconf of the app | ||
| for _app in app_names: | ||
| reload_urlconf(urlconf=_app) | ||
|
|
||
| # reload the core urlconf | ||
| reload_urlconf(urlconf='rdmo.core.urls') | ||
|
|
||
| # reload the testcase settings urlconf | ||
| reload_urlconf(root_urlconf=root_urlconf) | ||
|
|
||
| get_resolver()._populate() | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def enable_terms_of_use(settings): # noqa: PT004 | ||
| settings.ACCOUNT_TERMS_OF_USE = True | ||
| reload_urls('rdmo.accounts.urls') | ||
|
|
||
| yield | ||
|
|
||
| # revert settings to initial state | ||
| settings.ACCOUNT_TERMS_OF_USE = False | ||
| # 🔹 Reload URLs to reflect the changes | ||
| reload_urls('rdmo.accounts.urls') | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def enable_socialaccount(settings): # noqa: PT004 | ||
| # Arrange: this fixture enable and initializes the allauth.sociallaccount | ||
| # INSTALLED_APPS already has "allauth.socialaccount","allauth.socialaccount.providers.dummy" | ||
| settings.SOCIALACCOUNT = True | ||
| settings.SOCIALACCOUNT_SIGNUP = True | ||
|
|
||
| assert reverse("dummy_login") # Ensure the route exists | ||
|
|
||
| yield # Run test | ||
|
|
||
| # 🔹 Cleanup: reset settings | ||
| settings.SOCIALACCOUNT = False | ||
| settings.SOCIALACCOUNT_SIGNUP = False | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.