예제 #1
0
    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')])
예제 #2
0
    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))
예제 #3
0
    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')])
예제 #4
0
    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'])
예제 #5
0
    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))