From cb66d003278ac9cb275268eeb8860fc36e92e1ee Mon Sep 17 00:00:00 2001
From: Valentin Deniaud <vdeniaud@entrouvert.com>
Date: Tue, 11 Jun 2019 11:08:24 +0200
Subject: [PATCH] views: allow limiting ProfileView to credentials (#33550)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Users who are forced to enable an authentication factor are redirected
to their profile. For clarity, we don't want them seeing account
management blocks when this happens.

Note : la template de profil dans a2 a l'air assez délaissée, mais il
faudrait la modifier pour que le commit ait du sens. Et de toute façon
faire une ou deux modif dans publik-base-theme.
---
 src/authentic2/views.py | 47 ++++++++++++++++++++++++-----------------
 1 file changed, 28 insertions(+), 19 deletions(-)

diff --git a/src/authentic2/views.py b/src/authentic2/views.py
index 9ccd3f99..0041c87d 100644
--- a/src/authentic2/views.py
+++ b/src/authentic2/views.py
@@ -430,8 +430,8 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
     def get_context_data(self, **kwargs):
         context = super(ProfileView, self).get_context_data(**kwargs)
         request = self.request
-        auth_level = int(request.GET.get('auth_level', 0))
-        frontends = utils.get_backends('AUTH_FRONTENDS', required_auth_level=auth_level)
+        filter_by_auth_level = int(request.GET.get('auth_level', 0))
+        frontends = utils.get_backends('AUTH_FRONTENDS', filter_by_auth_level)
 
         if request.method == "POST":
             for frontend in frontends:
@@ -441,12 +441,22 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
                         if request.session.test_cookie_worked():
                             request.session.delete_test_cookie()
                         return frontend.post(request, form, None, '/profile')
+
+        if not filter_by_auth_level:
+            self.get_user_attributes_context(context)
+
+        self.get_credential_management_context(context, frontends)
+        hooks.call_hooks('modify_context_data', self, context)
+        return context
+
+    def get_user_attributes_context(self, context):
         # User attributes management
+        user = self.request.user
         profile = []
         field_names = app_settings.A2_PROFILE_FIELDS
         if not field_names:
             field_names = list(app_settings.A2_REGISTRATION_FIELDS)
-            for field_name in getattr(request.user, 'USER_PROFILE', []):
+            for field_name in getattr(user, 'USER_PROFILE', []):
                 if field_name not in field_names:
                     field_names.append(field_name)
             qs = models.Attribute.objects.filter(Q(user_editable=True) | Q(user_visible=True))
@@ -471,7 +481,7 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
                 if not attribute.user_visible:
                     continue
                 html_value = attribute.get_kind().get('html_value', lambda a, b: b)
-                qs = models.AttributeValue.objects.with_owner(request.user)
+                qs = models.AttributeValue.objects.with_owner(user)
                 qs = qs.filter(attribute=attribute)
                 qs = qs.select_related()
                 value = [at_value.to_python() for at_value in qs]
@@ -482,12 +492,12 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
             else:
                 # fallback to model attributes
                 try:
-                    field = request.user._meta.get_field(field_name)
+                    field = user._meta.get_field(field_name)
                 except FieldDoesNotExist:
                     continue
                 if not title:
                     title = field.verbose_name
-                value = getattr(self.request.user, field_name, None)
+                value = getattr(user, field_name, None)
                 attribute = models.Attribute(name=field_name, label=title)
 
             raw_value = None
@@ -501,9 +511,18 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
             if value or app_settings.A2_PROFILE_DISPLAY_EMPTY_FIELDS:
                 profile.append((title, value))
                 attributes.append({'attribute': attribute, 'values': raw_value})
+        context.update({
+            'profile': profile,
+            'attributes': attributes,
+            'allow_account_deletion': app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT,
+            'allow_profile_edit': EditProfile.can_edit_profile(),
+            'allow_email_change': app_settings.A2_PROFILE_CAN_CHANGE_EMAIL,
+            # TODO: deprecated should be removed when publik-base-theme is updated
+            'allow_password_change': utils.user_can_change_password(request=self.request),
+        })
 
-        # Credentials management
-        parameters = {'request': request,
+    def get_credential_management_context(self, context, frontends):
+        parameters = {'request': self.request,
                       'context': context}
         profiles = [utils.get_authenticator_method(frontend, 'profile', parameters) for frontend in frontends]
         # Old frontends data structure for templates
@@ -517,22 +536,12 @@ class ProfileView(cbv.TemplateNamesMixin, TemplateView):
         if app_settings.A2_PROFILE_CAN_MANAGE_FEDERATION:
             for idp_backend in idp_backends:
                 if hasattr(idp_backend, 'federation_management'):
-                    federation_management.extend(idp_backend.federation_management(request))
+                    federation_management.extend(idp_backend.federation_management(self.request))
         context.update({
             'frontends_block': blocks,
             'frontends_block_by_id': blocks_by_id,
-            'profile': profile,
-            'attributes': attributes,
-            'allow_account_deletion': app_settings.A2_REGISTRATION_CAN_DELETE_ACCOUNT,
-            'allow_profile_edit': EditProfile.can_edit_profile(),
-            'allow_email_change': app_settings.A2_PROFILE_CAN_CHANGE_EMAIL,
-            # TODO: deprecated should be removed when publik-base-theme is updated
-            'allow_password_change': utils.user_can_change_password(request=request),
             'federation_management': federation_management,
-            'auth_level': auth_level,
         })
-        hooks.call_hooks('modify_context_data', self, context)
-        return context
 
 profile = login_required(ProfileView.as_view())
 
-- 
2.20.1

