From 9d2a11b874c9f68a5361a37305cf5b5f4bfb8c41 Mon Sep 17 00:00:00 2001 From: Sunil Mohan Adapa Date: Wed, 13 Mar 2024 00:29:05 -0700 Subject: [PATCH] users: Add email address field when creating/updating user accounts Closes: #1826. Signed-off-by: Sunil Mohan Adapa Reviewed-by: Veiko Aasa --- plinth/modules/users/forms.py | 28 +++++++++++++------ plinth/modules/users/tests/test_functional.py | 28 ++++++++++++++++++- plinth/tests/functional/__init__.py | 4 ++- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/plinth/modules/users/forms.py b/plinth/modules/users/forms.py index 4abc8bcf8..5f889bb48 100644 --- a/plinth/modules/users/forms.py +++ b/plinth/modules/users/forms.py @@ -59,6 +59,18 @@ def _create_django_groups(): return group_choices +class EmailFieldMixin: + """Mixin to set common properties for the email field.""" + + def __init__(self, *args, **kwargs): + """Set basic properties for the email field.""" + super().__init__(*args, **kwargs) + + self.fields['email'].help_text = _( + 'Optional. Used to send emails to reset password and important ' + 'notifications.') + + class GroupsFieldMixin: """Mixin to set common properties for the group field.""" @@ -146,8 +158,8 @@ class PasswordConfirmForm(forms.Form): return confirm_password -class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, - plinth.forms.LanguageSelectionFormMixin, +class CreateUserForm(ValidNewUsernameCheckMixin, EmailFieldMixin, + GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, PasswordConfirmForm, UserCreationForm): """Custom user create form. @@ -161,8 +173,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, class Meta(UserCreationForm.Meta): """Metadata to control automatic form building.""" - fields = ('username', 'password1', 'password2', 'groups', 'language', - 'confirm_password') + fields = ('username', 'email', 'password1', 'password2', 'groups', + 'language', 'confirm_password') widgets = { 'groups': plinth.forms.CheckboxSelectMultiple(), } @@ -219,8 +231,8 @@ class CreateUserForm(ValidNewUsernameCheckMixin, GroupsFieldMixin, class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, - GroupsFieldMixin, plinth.forms.LanguageSelectionFormMixin, - forms.ModelForm): + EmailFieldMixin, GroupsFieldMixin, + plinth.forms.LanguageSelectionFormMixin, forms.ModelForm): """When user info is changed, also updates LDAP user.""" username = USERNAME_FIELD @@ -238,8 +250,8 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, PasswordConfirmForm, class Meta: """Metadata to control automatic form building.""" - fields = ('username', 'groups', 'ssh_keys', 'language', 'is_active', - 'confirm_password') + fields = ('username', 'email', 'groups', 'ssh_keys', 'language', + 'is_active', 'confirm_password') model = User widgets = { 'groups': plinth.forms.CheckboxSelectMultipleWithReadOnly(), diff --git a/plinth/modules/users/tests/test_functional.py b/plinth/modules/users/tests/test_functional.py index 063c7f548..d877ff81e 100644 --- a/plinth/modules/users/tests/test_functional.py +++ b/plinth/modules/users/tests/test_functional.py @@ -65,8 +65,9 @@ def test_create_user(session_browser): if functional.user_exists(session_browser, 'alice'): functional.delete_user(session_browser, 'alice') - functional.create_user(session_browser, 'alice') + functional.create_user(session_browser, 'alice', email='alice@example.com') assert functional.user_exists(session_browser, 'alice') + assert _get_email(session_browser, 'alice') == 'alice@example.com' def test_rename_user(session_browser): @@ -133,6 +134,17 @@ def test_users_cannot_connect_passwordless_over_ssh(session_browser, tmp_path_factory) +def test_update_user(session_browser): + """Test changing properties of a user.""" + functional.create_user(session_browser, 'alice', email='alice@example.com') + + # Update email + _set_email(session_browser, 'alice', 'alice1@example.com') + assert _get_email(session_browser, 'alice') == 'alice1@example.com' + _set_email(session_browser, 'alice', 'alice2@example.com') + assert _get_email(session_browser, 'alice') == 'alice2@example.com' + + @pytest.mark.parametrize('language_code', _language_codes.values()) def test_change_language(session_browser, language_code): """Test changing the language.""" @@ -254,6 +266,20 @@ def _rename_user(browser, old_name, new_name): functional.submit(browser, form_class='form-update') +def _set_email(browser, username, email): + """Set the email field value for a user.""" + functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) + browser.find_by_id('id_email').fill(email) + browser.find_by_id('id_confirm_password').fill(_admin_password) + functional.submit(browser, form_class='form-update') + + +def _get_email(browser, username): + """Return the email field value for a user.""" + functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) + return browser.find_by_id('id_email').value + + def _set_language(browser, language_code): username = functional.config['DEFAULT']['username'] functional.visit(browser, '/plinth/sys/users/{}/edit/'.format(username)) diff --git a/plinth/tests/functional/__init__.py b/plinth/tests/functional/__init__.py index e4349cf42..c08d7753e 100644 --- a/plinth/tests/functional/__init__.py +++ b/plinth/tests/functional/__init__.py @@ -599,7 +599,7 @@ def get_forwarders(browser): ############################## -def create_user(browser, name, password=None, groups=[]): +def create_user(browser, name, password=None, groups=[], email=None): """Create a user with password and user groups.""" nav_to_module(browser, 'users') @@ -612,6 +612,8 @@ def create_user(browser, name, password=None, groups=[]): browser.find_by_id('id_username').fill(name) browser.find_by_id('id_password1').fill(password) browser.find_by_id('id_password2').fill(password) + if email: + browser.find_by_id('id_email').fill(email) for group in groups: browser.find_by_xpath(