3434from lms .djangoapps .certificates .data import CertificateStatuses
3535from openedx .core .djangoapps .ace_common .tests .mixins import EmailTemplateTagMixin
3636from openedx .core .djangoapps .embargo .models import Country , GlobalRestrictedCountry
37+ from openedx .core .djangoapps .site_configuration .tests .test_util import with_site_configuration
3738from openedx .core .djangoapps .user_api .accounts import PRIVATE_VISIBILITY
3839from openedx .core .djangoapps .user_api .accounts .api import (
3940 get_account_settings ,
@@ -166,6 +167,30 @@ def test_update_username_provided(self):
166167 with pytest .raises (UserNotAuthorized ):
167168 update_account_settings (self .different_user , {"name" : "Pluto" }, username = self .user .username )
168169
170+ @with_site_configuration (configuration = {"extended_profile_fields" : ["department" ]})
171+ def test_update_username_provided_with_extended_profile (self ):
172+ """Test that extended profile is saved when username is provided to update_account_settings."""
173+ extended_profile_data = [{"field_name" : "department" , "field_value" : "Engineering" }]
174+
175+ update_account_settings (self .user , {"extended_profile" : extended_profile_data , "name" : "Donald Duck" })
176+ account_settings = get_account_settings (self .default_request )[0 ]
177+ self .assertEqual (extended_profile_data , account_settings ["extended_profile" ])
178+ self .assertEqual ("Donald Duck" , account_settings ["name" ])
179+
180+ update_account_settings (
181+ self .user , {"extended_profile" : extended_profile_data , "name" : "Mickey Mouse" }, username = self .user .username
182+ )
183+ account_settings = get_account_settings (self .default_request )[0 ]
184+ self .assertEqual (extended_profile_data , account_settings ["extended_profile" ])
185+ self .assertEqual ("Mickey Mouse" , account_settings ["name" ])
186+
187+ with pytest .raises (UserNotAuthorized ):
188+ update_account_settings (
189+ self .different_user ,
190+ {"extended_profile" : extended_profile_data , "name" : "Pluto" },
191+ username = self .user .username ,
192+ )
193+
169194 def test_update_non_existent_user (self ):
170195 with pytest .raises (UserNotAuthorized ):
171196 update_account_settings (self .user , {}, username = "does_not_exist" )
@@ -619,64 +644,68 @@ def test_update_extended_profile_with_meta_only(self):
619644 self .assertEqual (meta ["title" ], "Software Engineer" )
620645 self .assertEqual (user_profile .bio , "Updated bio" )
621646
622- def test_update_extended_profile_with_form (self ):
647+ @patch ("openedx.core.djangoapps.user_api.accounts.api.validate_and_get_extended_profile_form" )
648+ def test_update_extended_profile_with_form (self , mock_validate_and_get_form ):
623649 """
624650 Test updating extended profile with a validated form
625651 """
626- mock_form = Mock ()
627- mock_instance = Mock ()
628- mock_instance .user = self .user
629- mock_form .save .return_value = mock_instance
630- update_data = {"extended_profile" : [{"field_name" : "department" , "field_value" : "Engineering" }]}
652+ extended_profile_data = [{"field_name" : "department" , "field_value" : "Engineering" }]
653+ mock_form = Mock (save = Mock (return_value = Mock (user = self .user )))
654+ mock_validate_and_get_form .return_value = (mock_form , {})
631655
632- update_account_settings (self .user , update_data )
656+ update_account_settings (self .user , { "extended_profile" : extended_profile_data } )
633657
658+ mock_validate_and_get_form .assert_called_once_with (extended_profile_data , self .user )
634659 mock_form .save .assert_called_once_with (commit = False )
635- mock_instance .save .assert_called_once ()
636- user_profile = UserProfile .objects .get (user = self .user )
637- meta = user_profile .get_meta ()
660+ mock_form .save .return_value .save .assert_called_once ()
661+ meta = UserProfile .objects .get (user = self .user ).get_meta ()
638662 self .assertEqual (meta ["department" ], "Engineering" )
639663
640- def test_update_extended_profile_with_form_new_instance (self ):
664+ @patch ("openedx.core.djangoapps.user_api.accounts.api.validate_and_get_extended_profile_form" )
665+ def test_update_extended_profile_with_form_new_instance (self , mock_validate_and_get_form ):
641666 """
642667 Test updating extended profile with a form for a new instance
643668 """
644- mock_form = Mock ()
645- mock_instance = Mock ()
646- mock_instance .user = None
647- mock_form .save .return_value = mock_instance
648- update_data = {"extended_profile" : [{"field_name" : "department" , "field_value" : "Engineering" }]}
669+ extended_profile_data = [{"field_name" : "department" , "field_value" : "Engineering" }]
670+ mock_instance = Mock (user = None )
671+ mock_form = Mock (save = Mock (return_value = mock_instance ))
672+ mock_validate_and_get_form .return_value = (mock_form , {})
649673
650- update_account_settings (self .user , update_data )
674+ update_account_settings (self .user , { "extended_profile" : extended_profile_data } )
651675
652- self . assertEqual ( mock_instance . user , self .user )
676+ mock_validate_and_get_form . assert_called_once_with ( extended_profile_data , self .user )
653677 mock_form .save .assert_called_once_with (commit = False )
678+ self .assertEqual (mock_instance .user , self .user )
654679 mock_instance .save .assert_called_once ()
655680
681+ @patch ("openedx.core.djangoapps.user_api.accounts.api.validate_and_get_extended_profile_form" )
656682 @ddt .data (
657683 (ValidationError ("Invalid field value" ), "Extended profile validation failed" ),
658684 (IntegrityError ("Duplicate entry" ), "Extended profile integrity error" ),
659685 (DatabaseError ("Connection lost" ), "Database error saving extended profile" ),
660686 )
661687 @ddt .unpack
662- def test_update_extended_profile_form_save_error (self , exception , expected_dev_msg ):
688+ def test_update_extended_profile_form_save_error (self , exception , expected_dev_msg , mock_validate_and_get_form ):
663689 """
664- Test that errors during form save are logged, cause an AccountUpdateError with appropriate messages,
665- and do not leave partial updates
690+ Test that errors during form save cause an AccountUpdateError with appropriate messages,
691+ and do not leave partial updates.
666692 """
693+ extended_profile_data = [{"field_name" : "department" , "field_value" : "Engineering" }]
667694 mock_form = Mock ()
668695 mock_form .save .side_effect = exception
669- update_data = { "extended_profile" : [{ "field_name" : "department" , "field_value" : "Engineering" }]}
696+ mock_validate_and_get_form . return_value = ( mock_form , {})
670697
671698 with pytest .raises (AccountUpdateError ) as context_manager :
672- update_account_settings (self .user , update_data )
699+ update_account_settings (self .user , { "extended_profile" : extended_profile_data } )
673700
674701 self .assertIn (expected_dev_msg , context_manager .value .developer_message )
675702 self .assertIsNotNone (context_manager .value .user_message )
676703
677- user_profile = UserProfile .objects .get (user = self .user )
678- meta = user_profile .get_meta ()
679- # The meta update should also be rolled back, so no extended profile data is persisted.
704+ mock_validate_and_get_form .assert_called_once_with (extended_profile_data , self .user )
705+ mock_form .save .assert_called_once_with (commit = False )
706+
707+ # The meta update is in the same transaction, it should be rolled back.
708+ meta = UserProfile .objects .get (user = self .user ).get_meta ()
680709 self .assertNotIn ("department" , meta )
681710
682711 def test_update_extended_profile_without_extended_profile_data (self ):
@@ -690,23 +719,6 @@ def test_update_extended_profile_without_extended_profile_data(self):
690719 user_profile = UserProfile .objects .get (user = self .user )
691720 self .assertEqual (user_profile .bio , "Updated bio" )
692721
693- def test_update_extended_profile_form_without_data_in_update (self ):
694- """
695- Test that form is saved even if extended_profile is not in update data
696- """
697- mock_form = Mock ()
698- mock_instance = Mock ()
699- mock_instance .user = self .user
700- mock_form .save .return_value = mock_instance
701- update_data = {"bio" : "Updated bio" }
702-
703- update_account_settings (self .user , update_data )
704-
705- mock_form .save .assert_called_once_with (commit = False )
706- mock_instance .save .assert_called_once ()
707- user_profile = UserProfile .objects .get (user = self .user )
708- self .assertEqual (user_profile .bio , "Updated bio" )
709-
710722
711723@patch ('openedx.core.djangoapps.user_api.accounts.image_helpers._PROFILE_IMAGE_SIZES' , [50 , 10 ])
712724@patch .dict (
0 commit comments