def test_associate_multi_with_user_id_collision_raises(self): firebase_auth_services.associate_auth_id_with_user_id( auth_domain.AuthIdUserIdPair('aid1', 'uid1')) with self.assertRaisesRegexp(Exception, 'already associated'): firebase_auth_services.associate_multi_auth_ids_with_user_ids( [auth_domain.AuthIdUserIdPair('aid1', 'uid1'), auth_domain.AuthIdUserIdPair('aid2', 'uid2'), auth_domain.AuthIdUserIdPair('aid3', 'uid3')])
def reduce(key, values): # The reduce() function must be static, so we manually create a "cls" # variable instead of changing the function into a classmethod. cls = PopulateFirebaseAccountsOneOffJob if key == cls.POPULATED_KEY: yield (cls.AUDIT_KEY, len(values)) return elif key in (cls.SUPER_ADMIN_ACK, cls.SYSTEM_COMMITTER_ACK): yield (key, values) return # NOTE: This is only sorted to make unit testing easier. user_fields = sorted(ast.literal_eval(v) for v in values) user_records = [ firebase_auth.ImportUserRecord( uid=auth_id, email=email, email_verified=True, custom_claims=('{"role":"%s"}' % feconf.FIREBASE_ROLE_SUPER_ADMIN if user_is_super_admin else None)) for auth_id, _, email, user_is_super_admin in user_fields ] # The Firebase Admin SDK places a hard-limit on the number of users that # can be "imported" in a single call. To compensate, we break up the # users into chunks. offsets = python_utils.RANGE( 0, len(user_records), cls.MAX_USERS_FIREBASE_CAN_IMPORT_PER_CALL) results = (cls.populate_firebase( [r for r in record_group if r is not None]) for record_group in utils.grouper( user_records, cls.MAX_USERS_FIREBASE_CAN_IMPORT_PER_CALL)) assocs_to_create = [] for offset, (result, exception) in python_utils.ZIP(offsets, results): if exception is not None: yield (cls.ERROR_KEY, repr(exception)) else: successful_indices = set( python_utils.RANGE(result.success_count + result.failure_count)) for error in result.errors: successful_indices.remove(error.index) debug_info = 'Import user_id=%r failed: %s' % ( user_fields[offset + error.index][1], error.reason) yield (cls.ERROR_KEY, debug_info) assocs_to_create.extend( auth_domain.AuthIdUserIdPair(*user_fields[offset + i][:2]) for i in successful_indices) if assocs_to_create: firebase_auth_services.associate_multi_auth_ids_with_user_ids( assocs_to_create) yield (cls.SUCCESS_KEY, len(assocs_to_create))
def test_associate_multi_with_auth_id_collision_raises(self): firebase_auth_services.associate_auth_id_with_user_id( auth_domain.AuthIdUserIdPair('aid1', 'uid1')) # Erase the user_id collision, but leave the auth_id collision. auth_models.UserIdByFirebaseAuthIdModel.delete_by_id('aid1') with self.assertRaisesRegexp(Exception, 'already associated'): firebase_auth_services.associate_multi_auth_ids_with_user_ids( [auth_domain.AuthIdUserIdPair('aid1', 'uid1'), auth_domain.AuthIdUserIdPair('aid2', 'uid2'), auth_domain.AuthIdUserIdPair('aid3', 'uid3')])
def test_associate_multi_without_collisions(self): firebase_auth_services.associate_multi_auth_ids_with_user_ids( [auth_domain.AuthIdUserIdPair('aid1', 'uid1'), auth_domain.AuthIdUserIdPair('aid2', 'uid2'), auth_domain.AuthIdUserIdPair('aid3', 'uid3')]) self.assertEqual( [firebase_auth_services.get_user_id_from_auth_id('aid1'), firebase_auth_services.get_user_id_from_auth_id('aid2'), firebase_auth_services.get_user_id_from_auth_id('aid3')], ['uid1', 'uid2', 'uid3'])
def reduce(key, values): if key == POPULATED_KEY: yield (AUDIT_KEY, len(values)) return elif key == SYSTEM_COMMITTER_ACK: yield (SYSTEM_COMMITTER_ACK, values) return try: # NOTE: "app" is the term Firebase uses for the "entry point" to the # Firebase SDK. Oppia only has one server, so it only needs to # instantiate one app. firebase_connection = firebase_admin.initialize_app() except Exception as exception: yield (WARNING_KEY, repr(exception)) return # NOTE: This is only sorted to make unit testing easier. user_fields = sorted(ast.literal_eval(v) for v in values) user_records = [ firebase_auth.ImportUserRecord(uid=auth_id, email=email, email_verified=True) for auth_id, _, email in user_fields ] # The Firebase Admin SDK places a hard-limit on the number of users that # can be "imported" in a single call. To compensate, we break up the # users into chunks. offsets = python_utils.RANGE(0, len(user_records), MAX_USERS_FIREBASE_CAN_IMPORT_PER_CALL) results = (_populate_firebase( [record for record in record_group if record]) for record_group in _grouper( user_records, MAX_USERS_FIREBASE_CAN_IMPORT_PER_CALL)) assocs_to_create = [] for offset, (result, exception) in python_utils.ZIP(offsets, results): if exception is not None: yield (FAILURE_KEY, repr(exception)) else: successful_indices = set( python_utils.RANGE(result.success_count + result.failure_count)) for error in result.errors: successful_indices.remove(error.index) debug_info = ( 'Import user_id=%r failed: %s' % (user_fields[offset + error.index][1], error.reason)) yield (FAILURE_KEY, debug_info) assocs_to_create.extend( auth_domain.AuthIdUserIdPair(*user_fields[offset + i][:2]) for i in successful_indices) if assocs_to_create: firebase_auth_services.associate_multi_auth_ids_with_user_ids( assocs_to_create) yield (SUCCESS_KEY, len(assocs_to_create)) try: # NOTE: This is not dangerous. We are just deleting the resources # used to form a connection to Firebase servers. firebase_admin.delete_app(firebase_connection) except Exception as exception: yield (WARNING_KEY, repr(exception))