/accounts/: compute profile completion ratio (#88287) #280

Merged
pmarillonnet merged 1 commits from wip/88287-accounts-profile-completion-ratio into main 2024-04-18 11:23:10 +02:00
4 changed files with 93 additions and 0 deletions

View File

@ -284,6 +284,9 @@ default_settings = dict(
definition='Set a random password on request to reset the password from the front-office',
),
A2_ACCOUNTS_URL=Setting(default=None, definition='IdP has no account page, redirect to this one.'),
A2_ACCOUNTS_DISPLAY_COMPLETION_RATIO=Setting(
default=False, definition='Display user\'s profile completion ratio.'
smihai marked this conversation as resolved Outdated

Pour être plus explicite "A2_ACCOUNTS_DISPLAY_PROFILE_COMPLETION_RATIO" ?

Pour être plus explicite "A2_ACCOUNTS_DISPLAY_PROFILE_COMPLETION_RATIO" ?

Je croyais ça entendu dans le A2_ACCOUNTS_ qui préfixe toutes les settings relatives à l’interface /accounts/ de gestion du profil, ça me va de laisser ainsi ce nom de setting déjà assez long, mais si tu trouves ça ambigu alors je modifie, sûr.

Je croyais ça entendu dans le A2_*ACCOUNTS*_ qui préfixe toutes les settings relatives à l’interface /accounts/ de gestion du profil, ça me va de laisser ainsi ce nom de setting déjà assez long, mais si tu trouves ça ambigu alors je modifie, sûr.

D'acc.

D'acc.
),
A2_CACHE_ENABLED=Setting(default=True, definition='Disable all cache decorators for testing purpose.'),
A2_ALLOW_PHONE_AUTHN_MANAGEMENT=Setting(
default=False,

View File

@ -47,6 +47,12 @@
{% endif %}
{% endif %}
<div id="a2-profile" class="a2-profile-block">
{% if completion_ratio is not None %}
<div id="a2-profile-completion-ratio">
{% widthratio completion_ratio 1 100 as completion_percent %}
{% blocktranslate %}You have completed {{ completion_percent }}% of your user profile.{% endblocktranslate %}
</div>
{% endif %}
{% if attributes %}
<dl>
{% for attribute in attributes %}

View File

@ -821,6 +821,29 @@ class ProfileView(HomeURLMixin, cbv.TemplateNamesMixin, TemplateView):
and authenticator.phone_identifier_field.user_editable
and not authenticator.phone_identifier_field.disabled
)
completion_ratio = None
if app_settings.A2_ACCOUNTS_DISPLAY_COMPLETION_RATIO and (
total_attrs := models.Attribute.objects.filter(
disabled=False,
user_visible=True,
user_editable=True,
)
):
total_count = total_attrs.count()
filled_attrs_count = (
models.AttributeValue.objects.filter(
content_type=ContentType.objects.get_for_model(get_user_model()),
object_id=self.request.user.id,
attribute_id__in=total_attrs,
content__isnull=False,
)
.order_by('attribute_id')
.distinct('attribute_id')
.count()
)
completion_ratio = round(filled_attrs_count / total_count, 2)
context.update(
{
'frontends_block': blocks,
@ -835,6 +858,7 @@ class ProfileView(HomeURLMixin, cbv.TemplateNamesMixin, TemplateView):
# TODO: deprecated should be removed when publik-base-theme is updated
'allow_password_change': utils_misc.user_can_change_password(request=request),
'federation_management': federation_management,
'completion_ratio': completion_ratio,
}
)

View File

@ -531,3 +531,63 @@ def test_account_view_boolean(app, simple_user, settings):
simple_user.attributes.accept = False
resp = app.get(reverse('account_management'))
assert 'Vrai' not in resp.text
def test_account_profile_completion_ratio(app, simple_user, settings):
settings.A2_ACCOUNTS_DISPLAY_COMPLETION_RATIO = True
Attribute.objects.all().delete()
for i in range(8):
Attribute.objects.create(
name=f'attr_{i}',
label=f'Attribute {i}',
kind='string',
disabled=False,
multiple=False,
user_visible=True,
user_editable=True,
)
utils.login(app, simple_user)
resp = app.get(reverse('account_management'))
assert (
resp.pyquery('#a2-profile-completion-ratio')[0].text_content().strip()
== 'You have completed 0% of your user profile.'
)
simple_user.attributes.attr_0 = 'foo'
resp = app.get(reverse('account_management'))
assert (
resp.pyquery('#a2-profile-completion-ratio')[0].text_content().strip()
== 'You have completed 12% of your user profile.'
)
simple_user.attributes.attr_1 = 'bar'
resp = app.get(reverse('account_management'))
assert (
resp.pyquery('#a2-profile-completion-ratio')[0].text_content().strip()
== 'You have completed 25% of your user profile.'
)
# test that multiple attribute values don't jinx the stats
attr_2 = Attribute.objects.get(name='attr_2')
attr_2.multiple = True
attr_2.save()
simple_user.attributes.attr_2 = ['b', 'é', 'p', 'o']
resp = app.get(reverse('account_management'))
assert (
resp.pyquery('#a2-profile-completion-ratio')[0].text_content().strip()
== 'You have completed 38% of your user profile.'
)
# remaining attributes up to 100% completion
for i, percent in (('3', 50), ('4', 62), ('5', 75), ('6', 88), ('7', 100)):
setattr(simple_user.attributes, f'attr_{i}', i)
resp = app.get(reverse('account_management'))
assert (
resp.pyquery('#a2-profile-completion-ratio')[0].text_content().strip()
== f'You have completed {percent}% of your user profile.'
)
settings.A2_ACCOUNTS_DISPLAY_COMPLETION_RATIO = False
resp = app.get(reverse('account_management'))
assert not resp.pyquery('#a2-profile-completion-ratio')