Skip to content

User Management API with Phone Auth Support #49

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

Merged
merged 23 commits into from
Aug 11, 2017
Merged

Conversation

hiranya911
Copy link
Contributor

@hiranya911 hiranya911 commented Jul 13, 2017

Adds the basic user management operations to the auth module:

  • get_user()
  • get_user_by_email()
  • get_user_by_phone_number()
  • create_user()
  • update_user()
  • delete_user()

Also introduces the following new types for handling user account information:

  • auth.UserRecord
  • auth.UserInfo
  • auth.UserMetadata

go/firebase-python-user-mgt

Copy link

@bjornick bjornick left a comment

Choose a reason for hiding this comment

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

Sorry for the slow review


class TestUserRecord(object):

@pytest.mark.parametrize('data', INVALID_DICTS + [{}, {'foo':'bar'}])

Choose a reason for hiding this comment

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

it might be useful to mark why the last two elements are invalid in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


def test_get_user(self, user_mgt_app):
_instrument_user_manager(user_mgt_app, 200, testutils.resource('get_user.json'))
_check_user_record(auth.get_user('testuser', user_mgt_app))

Choose a reason for hiding this comment

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

It might be more readable if the values you are using here are constants. Then it becomes clearer that these should actually return results

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

def test_get_user_non_existing(self, user_mgt_app):
_instrument_user_manager(user_mgt_app, 200, '{"users":[]}')
with pytest.raises(auth.AuthError) as excinfo:
auth.get_user('testuser', user_mgt_app)

Choose a reason for hiding this comment

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

Might be better to use 'nonexistentuser'

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

def test_get_user_by_email_http_error(self, user_mgt_app):
_instrument_user_manager(user_mgt_app, 500, '{"error":"test"}')
with pytest.raises(auth.AuthError) as excinfo:
auth.get_user_by_email('testuser@example.com', user_mgt_app)

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done


Args:
uid: A user ID string.
app: An App instance (optional).

Choose a reason for hiding this comment

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

What is the behavior when an app isn't provided? where do the default values come from?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If an app is not explicitly provided (which is the more common use case), we use the default app returned by firebase_admin.get_app(). This is a feature common to all APIs in this library. Almost all public functions accept an optional app argument.

The equivalent logic in Java/Android SDKs is:

FirebaseAuth.getInstance() // Uses default app
FirebaseAuth.getInstance(app) // Uses the provided app

signal success.
"""

EMAIL_PATTERN = re.compile('^[^@]+@[^@]+$')

Choose a reason for hiding this comment

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

This seems too simplistic to be the regex pattern for emails. This is going to let a fair bit of invalid emails through. If this is all you are looking for, wouldn't it be simpler to just do:

parts = email.split('@')
if len(parts) == 2 and len(parts[0]) > 1 and len(parts[1] > 1:
   # Valid email address

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed the validation as suggested. We only need minimal checking here. Backend does more comprehensive checking.

self._session = session

def get_user(self, uid):
"""Gets the user data corresponding to the specified user ID."""
Copy link

Choose a reason for hiding this comment

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

all these get users are basically the same except for the error message. Does it make sense to have a shared implementation that takes in a parameter for the error messages?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

def create_user(self, **kwargs):
"""Creates a new user account with the specified properties."""
payload = {}
for key, value in _UserManager._CREATE_USER_FIELDS.items():
Copy link

Choose a reason for hiding this comment

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

I wonder if the kwargs validation/copying logic can be shared between create_user and update_user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@@ -14,48 +14,50 @@

Copy link

Choose a reason for hiding this comment

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

Can we split up the contents of this file? Maybe the validator and the user manager can go in a separate file?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done. Extracted to a new _user_mgt.py module. I had to change things around a little bit to break a few cyclic dependencies.

@hiranya911 hiranya911 assigned hiranya911 and unassigned bjornick Aug 1, 2017
@hiranya911
Copy link
Contributor Author

Made the suggested changes.

@hiranya911 hiranya911 assigned bjornick and unassigned hiranya911 Aug 1, 2017
@hiranya911 hiranya911 assigned hiranya911 and unassigned bjornick Aug 3, 2017
@dozer47528
Copy link

Hi Firebase team, I would like to know when Firebase team will release this new version include user management APIs ?

@grennis
Copy link

grennis commented Aug 11, 2017

Will there be a way to lookup multiple users at once? If I have a bunch of user IDs do I need to get their emails one at a time?

@hiranya911
Copy link
Contributor Author

@grennis Not in the initial release of this API. Can you create an issue for multi-user look up? We can consider it for a future iteration (or you can help us implement it ;) )

@grennis
Copy link

grennis commented Aug 11, 2017

Sure thing. Thanks and looking forward to the release of this PR.

@hiranya911 hiranya911 merged commit 4cfe33a into master Aug 11, 2017
@hiranya911 hiranya911 deleted the hkj-user-mgt branch August 11, 2017 23:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants