def test_get_user_not_found(self): """Test that UserNotFound is thrown if there is no user with username.""" with self.assertRaises(UserNotFound): get_account_settings(self.default_request, usernames=["does_not_exist"]) self.user.username = "******" request = self.request_factory.get("/api/user/v1/accounts/") request.user = self.user with self.assertRaises(UserNotFound): get_account_settings(request)
def test_get_username_provided(self): """Test the difference in behavior when a username is supplied to get_account_settings.""" account_settings = get_account_settings(self.default_request)[0] self.assertEqual(self.user.username, account_settings["username"]) account_settings = get_account_settings(self.default_request, usernames=[self.user.username])[0] self.assertEqual(self.user.username, account_settings["username"]) account_settings = get_account_settings(self.default_request, usernames=[self.different_user.username])[0] self.assertEqual(self.different_user.username, account_settings["username"])
def test_update_username_provided(self): """Test the difference in behavior when a username is supplied to update_account_settings.""" update_account_settings(self.user, {"name": "Mickey Mouse"}) account_settings = get_account_settings(self.default_request)[0] self.assertEqual("Mickey Mouse", account_settings["name"]) update_account_settings(self.user, {"name": "Donald Duck"}, username=self.user.username) account_settings = get_account_settings(self.default_request)[0] self.assertEqual("Donald Duck", account_settings["name"]) with self.assertRaises(UserNotAuthorized): update_account_settings(self.different_user, {"name": "Pluto"}, username=self.user.username)
def test_update_validation_error_for_enterprise( self, field_name_value, is_enterprise_user, is_synch_learner_profile_data, mock_auth_provider, mock_customer, ): mock_customer.return_value = {} if is_enterprise_user: mock_customer.return_value.update({ 'uuid': 'real-ent-uuid', 'name': 'Dummy Enterprise', 'identity_provider': 'saml-ubc' }) mock_auth_provider.return_value.sync_learner_profile_data = is_synch_learner_profile_data update_data = {field_name_value[0]: field_name_value[1]} # prevent actual email change requests with patch('openedx.core.djangoapps.user_api.accounts.api.student_views.do_email_change_request'): # expect field un-editability only when both of the following conditions are met if is_enterprise_user and is_synch_learner_profile_data: with self.assertRaises(AccountValidationError) as validation_error: update_account_settings(self.user, update_data) field_errors = validation_error.exception.field_errors self.assertEqual( "This field is not editable via this API", field_errors[field_name_value[0]]["developer_message"], ) else: update_account_settings(self.user, update_data) account_settings = get_account_settings(self.default_request)[0] if field_name_value[0] != "email": self.assertEqual(field_name_value[1], account_settings[field_name_value[0]])
def test_activate_account(self): # Create the account, which is initially inactive activation_key = create_account(self.USERNAME, self.PASSWORD, self.EMAIL) user = User.objects.get(username=self.USERNAME) request = RequestFactory().get("/api/user/v1/accounts/") request.user = user account = get_account_settings(request)[0] self.assertEqual(self.USERNAME, account["username"]) self.assertEqual(self.EMAIL, account["email"]) self.assertFalse(account["is_active"]) # Activate the account and verify that it is now active activate_account(activation_key) account = get_account_settings(request)[0] self.assertTrue(account['is_active'])
def test_set_single_social_link(self): social_links = [ dict(platform="facebook", social_link="https://www.facebook.com/{}".format(self.user.username)) ] update_account_settings(self.user, {"social_links": social_links}) account_settings = get_account_settings(self.default_request)[0] self.assertEqual(account_settings['social_links'], social_links)
def test_update_success_for_enterprise(self): EnterpriseCustomerUserFactory(user_id=self.user.id) level_of_education = "m" successful_update = { "level_of_education": level_of_education, } update_account_settings(self.user, successful_update) account_settings = get_account_settings(self.default_request)[0] self.assertEqual(level_of_education, account_settings["level_of_education"])
def learner_profile_context(request, profile_username, user_is_staff): """Context for the learner profile page. Args: logged_in_user (object): Logged In user. profile_username (str): username of user whose profile is requested. user_is_staff (bool): Logged In user has staff access. build_absolute_uri_func (): Returns: dict Raises: ObjectDoesNotExist: the specified profile_username does not exist. """ profile_user = User.objects.get(username=profile_username) logged_in_user = request.user own_profile = (logged_in_user.username == profile_username) account_settings_data = get_account_settings(request, profile_username) preferences_data = get_user_preferences(profile_user, profile_username) context = { 'data': { 'profile_user_id': profile_user.id, 'default_public_account_fields': settings.ACCOUNT_VISIBILITY_CONFIGURATION['public_fields'], 'default_visibility': settings.ACCOUNT_VISIBILITY_CONFIGURATION['default_visibility'], 'accounts_api_url': reverse("accounts_api", kwargs={'username': profile_username}), 'preferences_api_url': reverse('preferences_api', kwargs={'username': profile_username}), 'preferences_data': preferences_data, 'account_settings_data': account_settings_data, 'profile_image_upload_url': reverse('profile_image_upload', kwargs={'username': profile_username}), 'profile_image_remove_url': reverse('profile_image_remove', kwargs={'username': profile_username}), 'profile_image_max_bytes': settings.PROFILE_IMAGE_MAX_BYTES, 'profile_image_min_bytes': settings.PROFILE_IMAGE_MIN_BYTES, 'account_settings_page_url': reverse('account_settings'), 'has_preferences_access': (logged_in_user.username == profile_username or user_is_staff), 'own_profile': own_profile, 'country_options': list(countries), 'find_courses_url': marketing_link('COURSES'), 'language_options': settings.ALL_LANGUAGES, 'badges_logo': staticfiles_storage.url('certificates/images/backpack-logo.png'), 'badges_icon': staticfiles_storage.url('certificates/images/ico-mozillaopenbadges.png'), 'backpack_ui_img': staticfiles_storage.url('certificates/images/backpack-ui.png'), 'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME), }, 'disable_courseware_js': True, 'show_program_listing': ProgramsApiConfig.current().show_program_listing, } if badges_enabled(): context['data']['badges_api_url'] = reverse("badges_api:user_assertions", kwargs={'username': profile_username}) return context
def test_remove_social_link(self): original_facebook_link = dict(platform="facebook", social_link="https://www.facebook.com/myself") original_twitter_link = dict(platform="twitter", social_link="https://www.twitter.com/myself") update_account_settings(self.user, {"social_links": [original_facebook_link, original_twitter_link]}) removed_facebook_link = dict(platform="facebook", social_link="") update_account_settings(self.user, {"social_links": [removed_facebook_link]}) account_settings = get_account_settings(self.default_request)[0] self.assertEqual(account_settings['social_links'], [original_twitter_link])
def test_get_configuration_provided(self): """Test the difference in behavior when a configuration is supplied to get_account_settings.""" config = { "default_visibility": "private", "public_fields": [ 'email', 'name', ], } # With default configuration settings, email is not shared with other (non-staff) users. account_settings = get_account_settings(self.default_request, [self.different_user.username])[0] self.assertNotIn("email", account_settings) account_settings = get_account_settings( self.default_request, [self.different_user.username], configuration=config, )[0] self.assertEqual(self.different_user.email, account_settings["email"])
def learner_profile_context(logged_in_user, profile_username, user_is_staff, build_absolute_uri_func): """Context for the learner profile page. Args: logged_in_user (object): Logged In user. profile_username (str): username of user whose profile is requested. user_is_staff (bool): Logged In user has staff access. build_absolute_uri_func (): Returns: dict Raises: ObjectDoesNotExist: the specified profile_username does not exist. """ profile_user = User.objects.get(username=profile_username) own_profile = (logged_in_user.username == profile_username) account_settings_data = get_account_settings(logged_in_user, profile_username) # Account for possibly relative URLs. for key, value in account_settings_data['profile_image'].items(): if key.startswith(PROFILE_IMAGE_KEY_PREFIX): account_settings_data['profile_image'][key] = build_absolute_uri_func(value) preferences_data = get_user_preferences(profile_user, profile_username) sync_course = UserSyncCourse.objects.get(user=logged_in_user.id) context = { 'data': { 'profile_username': profile_user.username, 'profile_user_id': profile_user.id, 'default_public_account_fields': settings.ACCOUNT_VISIBILITY_CONFIGURATION['public_fields'], 'default_visibility': settings.ACCOUNT_VISIBILITY_CONFIGURATION['default_visibility'], 'accounts_api_url': reverse("accounts_api", kwargs={'username': profile_username}), 'preferences_api_url': reverse('preferences_api', kwargs={'username': profile_username}), 'preferences_data': preferences_data, 'account_settings_data': account_settings_data, 'profile_image_upload_url': reverse('profile_image_upload', kwargs={'username': profile_username}), 'profile_image_remove_url': reverse('profile_image_remove', kwargs={'username': profile_username}), 'profile_image_max_bytes': settings.PROFILE_IMAGE_MAX_BYTES, 'profile_image_min_bytes': settings.PROFILE_IMAGE_MIN_BYTES, 'account_settings_page_url': reverse('account_settings'), 'has_preferences_access': (logged_in_user.username == profile_username or user_is_staff), 'own_profile': own_profile, 'country_options': list(countries), 'language_options': settings.ALL_LANGUAGES, 'platform_name': microsite.get_value('platform_name', settings.PLATFORM_NAME), }, 'disable_courseware_js': True, 'sync_course': sync_course.sync, } return context
def test_update_sending_email_fails(self, send_mail): """Test what happens if all validation checks pass, but sending the email for email change fails.""" send_mail.side_effect = [Exception, None] less_naughty_update = { "name": "Mickey Mouse", "email": "*****@*****.**" } with self.assertRaises(AccountUpdateError) as context_manager: update_account_settings(self.user, less_naughty_update) self.assertIn("Error thrown from do_email_change_request", context_manager.exception.developer_message) # Verify that the name change happened, even though the attempt to send the email failed. account_settings = get_account_settings(self.default_request)[0] self.assertEqual("Mickey Mouse", account_settings["name"])
def test_add_social_links(self): original_social_links = [ dict(platform="facebook", social_link="https://www.facebook.com/{}".format(self.user.username)) ] update_account_settings(self.user, {"social_links": original_social_links}) extra_social_links = [ dict(platform="twitter", social_link="https://www.twitter.com/{}".format(self.user.username)), dict(platform="linkedin", social_link="https://www.linkedin.com/in/{}".format(self.user.username)), ] update_account_settings(self.user, {"social_links": extra_social_links}) account_settings = get_account_settings(self.default_request)[0] self.assertEqual( account_settings['social_links'], sorted(original_social_links + extra_social_links, key=lambda s: s['platform']), )
def test_create_account(self): # Create a new account, which should have empty account settings by default. create_account(self.USERNAME, self.PASSWORD, self.EMAIL) # Retrieve the account settings user = User.objects.get(username=self.USERNAME) request = RequestFactory().get("/api/user/v1/accounts/") request.user = user account_settings = get_account_settings(request)[0] # Expect a date joined field but remove it to simplify the following comparison self.assertIsNotNone(account_settings['date_joined']) del account_settings['date_joined'] # Expect all the values to be defaulted self.assertEqual(account_settings, { 'username': self.USERNAME, 'email': self.EMAIL, 'name': u'', 'gender': None, 'goals': None, 'is_active': False, 'level_of_education': None, 'mailing_address': None, 'year_of_birth': None, 'country': None, 'social_links': [], 'bio': None, 'profile_image': { 'has_image': False, 'image_url_full': request.build_absolute_uri('/static/default_50.png'), 'image_url_small': request.build_absolute_uri('/static/default_10.png'), }, 'requires_parental_consent': True, 'language_proficiencies': [], 'account_privacy': PRIVATE_VISIBILITY, 'accomplishments_shared': False, 'extended_profile': [], 'secondary_email': None, 'time_zone': None, 'course_certificates': None, })
def test_get_empty_social_links(self): account_settings = get_account_settings(self.default_request)[0] self.assertEqual(account_settings['social_links'], [])
def learner_profile_context(request, profile_username, user_is_staff): """Context for the learner profile page. Args: logged_in_user (object): Logged In user. profile_username (str): username of user whose profile is requested. user_is_staff (bool): Logged In user has staff access. build_absolute_uri_func (): Returns: dict Raises: ObjectDoesNotExist: the specified profile_username does not exist. """ profile_user = User.objects.get(username=profile_username) logged_in_user = request.user own_profile = (logged_in_user.username == profile_username) account_settings_data = get_account_settings(request, [profile_username])[0] preferences_data = get_user_preferences(profile_user, profile_username) context = { 'own_profile': own_profile, 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME), 'data': { 'profile_user_id': profile_user.id, 'default_public_account_fields': settings.ACCOUNT_VISIBILITY_CONFIGURATION['public_fields'], 'default_visibility': settings.ACCOUNT_VISIBILITY_CONFIGURATION['default_visibility'], 'accounts_api_url': reverse("accounts_api", kwargs={'username': profile_username}), 'preferences_api_url': reverse('preferences_api', kwargs={'username': profile_username}), 'preferences_data': preferences_data, 'account_settings_data': account_settings_data, 'profile_image_upload_url': reverse('profile_image_upload', kwargs={'username': profile_username}), 'profile_image_remove_url': reverse('profile_image_remove', kwargs={'username': profile_username}), 'profile_image_max_bytes': settings.PROFILE_IMAGE_MAX_BYTES, 'profile_image_min_bytes': settings.PROFILE_IMAGE_MIN_BYTES, 'account_settings_page_url': reverse('account_settings'), 'has_preferences_access': (logged_in_user.username == profile_username or user_is_staff), 'own_profile': own_profile, 'country_options': list(countries), 'find_courses_url': marketing_link('COURSES'), 'language_options': settings.ALL_LANGUAGES, 'badges_logo': staticfiles_storage.url('certificates/images/backpack-logo.png'), 'badges_icon': staticfiles_storage.url('certificates/images/ico-mozillaopenbadges.png'), 'backpack_ui_img': staticfiles_storage.url('certificates/images/backpack-ui.png'), 'platform_name': configuration_helpers.get_value('platform_name', settings.PLATFORM_NAME), 'social_platforms': settings.SOCIAL_PLATFORMS, }, 'show_program_listing': ProgramsApiConfig.is_enabled(), 'show_dashboard_tabs': True, 'disable_courseware_js': True, 'nav_hidden': True, 'records_url': get_credentials_records_url(), } if own_profile or user_is_staff: achievements_fragment = LearnerAchievementsFragmentView().render_to_fragment( request, username=profile_user.username, own_profile=own_profile, ) context['achievements_fragment'] = achievements_fragment if badges_enabled(): context['data']['badges_api_url'] = reverse("badges_api:user_assertions", kwargs={'username': profile_username}) return context
def submit_photos_for_verification(request): """Submit a photo verification attempt. Arguments: request (HttpRequest): The request to submit photos. Returns: HttpResponse: 200 on success, 400 if there are errors. """ # Check the required parameters missing_params = set(['face_image', 'photo_id_image']) - set(request.POST.keys()) if len(missing_params) > 0: msg = _("Missing required parameters: {missing}").format(missing=", ".join(missing_params)) return HttpResponseBadRequest(msg) # If the user already has valid or pending request, the UI will hide # the verification steps. For this reason, we reject any requests # for users that already have a valid or pending verification. if SoftwareSecurePhotoVerification.user_has_valid_or_pending(request.user): return HttpResponseBadRequest(_("You already have a valid or pending verification.")) # If the user wants to change his/her full name, # then try to do that before creating the attempt. if request.POST.get('full_name'): try: update_account_settings(request.user, {"name": request.POST.get('full_name')}) except UserNotFound: return HttpResponseBadRequest(_("No profile found for user")) except AccountValidationError: msg = _( "Name must be at least {min_length} characters long." ).format(min_length=NAME_MIN_LENGTH) return HttpResponseBadRequest(msg) # Create the attempt attempt = SoftwareSecurePhotoVerification(user=request.user) try: b64_face_image = request.POST['face_image'].split(",")[1] b64_photo_id_image = request.POST['photo_id_image'].split(",")[1] except IndexError: msg = _("Image data is not valid.") return HttpResponseBadRequest(msg) attempt.upload_face_image(b64_face_image.decode('base64')) attempt.upload_photo_id_image(b64_photo_id_image.decode('base64')) attempt.mark_ready() attempt.submit() account_settings = get_account_settings(request.user) # Send a confirmation email to the user context = { 'full_name': account_settings['name'], 'platform_name': settings.PLATFORM_NAME } subject = _("Verification photos received") message = render_to_string('emails/photo_submission_confirmation.txt', context) from_address = microsite.get_value('default_from_email', settings.DEFAULT_FROM_EMAIL) to_address = account_settings['email'] send_mail(subject, message, from_address, [to_address], fail_silently=False) return HttpResponse(200)