Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth): Add bulk get/delete methods #365

Merged
merged 11 commits into from
May 12, 2020
Merged

Conversation

rsgowman
Copy link
Member

@rsgowman rsgowman commented Feb 12, 2020

This PR allows callers to retrieve a list of users by unique identifier (uid, email, phone, federated provider uid) as well as to delete a list of users.

RELEASE NOTE: Added getUsers() and deleteUsers() APIs for retrieving and deleting user accounts in bulk.

@rsgowman rsgowman self-assigned this Feb 12, 2020
@rsgowman rsgowman force-pushed the rsgowman/bulk_get_users branch 2 times, most recently from b9c332d to 9f0c4ee Compare February 12, 2020 20:41
@@ -171,6 +178,37 @@ UserRecord getUserByPhoneNumber(String phoneNumber) throws FirebaseAuthException
return new UserRecord(response.getUsers().get(0), jsonFactory);
}

/**
* @pre identifiers != null
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are verified in the calling code. (As an alternative, we could just repeat the validation here.)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's drop the pre annotations. That's not really a convention we use. It is understood that the arguments passed to this class have already been validated. If you want add a class-level javadoc to indicate that explicitly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

* don't run into quota exceeded errors.
*/
// TODO(rsgowman): When/if the rate limit is relaxed, eliminate this helper.
private ApiFuture<DeleteUsersResult> slowDeleteUsersAsync(List<String> uids) throws Exception {
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We may need to do something similar for the other ports... There seems to be some elasticity such that the full test suite can often pass, but not if you run just the delete users tests in quick succession (as I did while testing).

@@ -0,0 +1,152 @@
/*
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

junit4 doesn't allow nested tests (and therefore doesn't allow nested setup/teardown functions.) The recommendation is to just split into a separate file, which is what I've done here.

Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rsgowman. Looks pretty great. Just pointed out a few tidbits to improve on.

Adding @egilmorez to review the docs portion.

src/main/java/com/google/firebase/auth/FirebaseAuth.java Outdated Show resolved Hide resolved
@@ -171,6 +178,37 @@ UserRecord getUserByPhoneNumber(String phoneNumber) throws FirebaseAuthException
return new UserRecord(response.getUsers().get(0), jsonFactory);
}

/**
* @pre identifiers != null
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's drop the pre annotations. That's not really a convention we use. It is understood that the arguments passed to this class have already been validated. If you want add a class-level javadoc to indicate that explicitly.

src/main/java/com/google/firebase/auth/UserRecord.java Outdated Show resolved Hide resolved
src/test/java/com/google/firebase/auth/FirebaseAuthIT.java Outdated Show resolved Hide resolved
src/test/java/com/google/firebase/auth/FirebaseAuthIT.java Outdated Show resolved Hide resolved
src/test/java/com/google/firebase/auth/GetUsersIT.java Outdated Show resolved Hide resolved

/**
* Returns the number of users that were deleted successfully (possibly zero). Users that did
* not exist prior to calling deleteUsersAsync() will be considered to be successfully
Copy link
Contributor

@egilmorez egilmorez Feb 18, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest code font/link for the method and present tense:

{@link deleteUsersAsync()} are considered

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* <p>There are no ordering guarantees; in particular, the nth entry in the users result list is
* not guaranteed to correspond to the nth entry in the input parameters list.
*
* <p>Only a maximum of 100 identifiers may be supplied. If more than 100 identifiers are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest just "A maximum . . . "

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* not guaranteed to correspond to the nth entry in the input parameters list.
*
* <p>Only a maximum of 100 identifiers may be supplied. If more than 100 identifiers are
* supplied, this method will immediately throw an IllegalArgumentException.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest "this method throws an {@link ...}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* <p>There are no ordering guarantees; in particular, the nth entry in the users result list is
* not guaranteed to correspond to the nth entry in the input parameters list.
*
* <p>Only a maximum of 100 identifiers may be supplied. If more than 100 identifiers are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we say "specified" above, this should probably work that way too.

Same on the present tense/link format in line 635.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done/done.

* Non-existing users will be considered to be successfully deleted, and will therefore be counted
* in the DeleteUsersResult.getSuccessCount() value.
*
* <p>Only a maximum of 1000 identifiers may be supplied. If more than 1000 identifiers are
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar changes here and next line as in 634 and 635.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done/done.

}

/**
* Set of user records, corresponding to the set of users that were requested. Only users
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest omitting this comma.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

import java.util.List;

/**
* Represents the response from identity toolkit for a batch delete request.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be "the identity toolkit?"

The article would normally be omitted only if this is a name, like uppercase "Identity Toolkit"

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe? I think I just copied it from UploadAccountResponse. Other locations use 'Google identity toolkit' (HttpErrorResponse, GetAccountInfoResponse, DownloadAccountResponse.) FirebaseUserManager uses 'Google Identity Toolkit'.

I've switched to 'Google Identity Toolkit'.

(Though note that this is an internal object, so shouldn't show up in the public api docs regardless.)

@Key("message")
private String message;

// A 'localId' field also exists here, but is not currently exposed in the admin sdk.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest caps for "Admin SDK."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

.setPassword("password"));

try {
// New users should not have a lastRefreshTimestamp set.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest @link or @code for all instances of this.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't a javadoc comment; is it conventional to use these types of annotations for inline docs like this?

i.e.:
clang-format src/test/java/com/google/firebase/auth/FirebaseAuthIT.java \
    --lines=140:215 --lines=328:356 --lines=822:838 -i
@rsgowman rsgowman removed their assignment Feb 20, 2020
Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @rsgowman. LGTM 👍

@hiranya911 hiranya911 removed their assignment Feb 21, 2020
Copy link

@cbonnie cbonnie left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added some comments, otherwise LGTM (reviewing on behalf of egilmore@).

}
return false;
}

/**
* Gets a page of users starting from the specified {@code pageToken}. Page size will be
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Page size is limited to..."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/**
* Deletes the users specified by the given identifiers.
*
* <p>Deleting a non-existing user won't generate an error. (i.e. this method is idempotent.)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest:

"Deleting a non-existing user does not generate an error (the method is idempotent). Non-existing users are considered to be successfully deleted and are therefore included in the DeleteUsersResult.getSuccessCount() value."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

* <p>A maximum of 1000 identifiers may be supplied. If more than 1000 identifiers are
* supplied, this method throws an {@link IllegalArgumentException}.
*
* <p>This API is currently rate limited at the server to 1 QPS. If you exceed this, you may get a
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest:

"This API has a rate limit of 1 QPS. Exceeding the limit may result in a quota exceeded error. If you want to delete more than 1000 users, we suggest adding a delay to ensure you don't exceed the limit."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
};
}

/**
* Imports the provided list of users into Firebase Auth. At most 1000 users can be imported at a
* time. This operation is optimized for bulk imports and will ignore checks on identifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest:

"Imports the provided list of users into Firebase Auth. You can import a maximum of 1000 users at a time. This operation is optimized for bulk imports and ignores checks on user identifiers."

(Not completely sure about the user identifiers part, I'm assuming that's what the operation would've checked for)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed the first two sentences as per your suggestion. I've changed the last to "This operation is optimized for bulk imports and does not check identifier uniqueness which could result in duplications".

import java.util.List;

/**
* Represents the request to lookup account information.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"look up" (verb)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

assertEquals(0, result.getFailureCount());
assertTrue(result.getErrors().isEmpty());

// Delete the user again, ensuring that everything still counts as a success.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggest: "Delete the user again to ensure that..."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}

/**
* The {@code batchDelete} endpoint is currently rate limited to 1qps. Use this test helper to
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"The {@code batchDelete} endpoint has a rate limit of 1 QPS. Use this test helper to ensure you don't exceed the quota."

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@hiranya911 hiranya911 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

Copy link
Contributor

@egilmorez egilmorez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@rsgowman rsgowman merged commit f8052c7 into master May 12, 2020
@rsgowman rsgowman deleted the rsgowman/bulk_get_users branch May 12, 2020 20:56
hiranya911 added a commit that referenced this pull request May 19, 2020
* Bump netty.version from 4.1.34.Final to 4.1.45.Final (#373)

Bumps `netty.version` from 4.1.34.Final to 4.1.45.Final.

Updates `netty-codec-http` from 4.1.34.Final to 4.1.45.Final
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](netty/netty@netty-4.1.34.Final...netty-4.1.45.Final)

Updates `netty-handler` from 4.1.34.Final to 4.1.45.Final
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](netty/netty@netty-4.1.34.Final...netty-4.1.45.Final)

Updates `netty-transport` from 4.1.34.Final to 4.1.45.Final
- [Release notes](https://github.com/netty/netty/releases)
- [Commits](netty/netty@netty-4.1.34.Final...netty-4.1.45.Final)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* feat(auth): Add bulk get/delete methods (#365)

This PR allows callers to retrieve a list of users by unique identifier (uid, email, phone, federated provider uid) as well as to delete a list of users.

RELEASE NOTE: Added getUsers() and deleteUsers() APIs for retrieving and deleting user accounts in bulk.

* chore: Setting the version of the Maven Javadoc plugin (#412)

* [chore] Release 6.13.0 (#413)

* [chore] Release 6.13.0 take 2 (#414)

* Upgated the gpg keys

* Added temp verify script

* Disabled tty for gpg import

* Removing temp verification script

* Updated publish commands

* [chore] Release 6.13.0 take 3 (#415)

* [chore] Release 6.13.0 take 4 (#416)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: rsgowman <rich@gowman.noip.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants