Skip to content

Commit b9ca619

Browse files
authored
Merge pull request #49 from renatoc8/master
Implemented FirebaseAuth.GetUser based on the Java implementation
2 parents 31e55ef + cced762 commit b9ca619

File tree

9 files changed

+535
-12
lines changed

9 files changed

+535
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Unreleased
22

3+
- [added] Implemented the `GetUserById()` API in the `FirebaseUserManager` class.
4+
35
-
46

57
# v1.4.0

FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,8 @@ public class FirebaseUserManagerTest
3232
[Fact]
3333
public void InvalidUidForUserRecord()
3434
{
35-
Assert.Throws<ArgumentException>(() => new UserRecord(null));
35+
Assert.Throws<ArgumentException>(() => new UserRecord((string)null));
36+
Assert.Throws<ArgumentException>(() => new UserRecord((GetAccountInfoResponse.User)null));
3637
Assert.Throws<ArgumentException>(() => new UserRecord(string.Empty));
3738
Assert.Throws<ArgumentException>(() => new UserRecord(new string('a', 129)));
3839
}
@@ -76,8 +77,16 @@ public async Task GetUserById()
7677
{
7778
var handler = new MockMessageHandler()
7879
{
79-
Response = new UserRecord("user1"),
80+
Response = new GetAccountInfoResponse()
81+
{
82+
Kind = "identitytoolkit#GetAccountInfoResponse",
83+
Users = new List<GetAccountInfoResponse.User>()
84+
{
85+
new GetAccountInfoResponse.User() { UserId = "user1" },
86+
},
87+
},
8088
};
89+
8190
var factory = new MockHttpClientFactory(handler);
8291
var userManager = new FirebaseUserManager(
8392
new FirebaseUserManagerArgs
@@ -114,7 +123,14 @@ public async Task UpdateUser()
114123
{
115124
var handler = new MockMessageHandler()
116125
{
117-
Response = new UserRecord("user1"),
126+
Response = new GetAccountInfoResponse()
127+
{
128+
Kind = "identitytoolkit#GetAccountInfoResponse",
129+
Users = new List<GetAccountInfoResponse.User>()
130+
{
131+
new GetAccountInfoResponse.User() { UserId = "user1" },
132+
},
133+
},
118134
};
119135
var factory = new MockHttpClientFactory(handler);
120136
var userManager = new FirebaseUserManager(

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,39 @@ public async Task<FirebaseToken> VerifyIdTokenAsync(
263263
.ConfigureAwait(false);
264264
}
265265

266+
/// <summary>
267+
/// Gets a <see cref="UserRecord"/> object containig information about the user who's
268+
/// user ID was specified in <paramref name="uid"/>.
269+
/// </summary>
270+
/// <param name="uid">The user ID for the user who's data is to be retrieved.</param>
271+
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
272+
/// a user with the specified user ID.</returns>
273+
/// <exception cref="ArgumentException">If user ID argument is null or empty.</exception>
274+
/// <exception cref="FirebaseException">If a user cannot be found with the specified user ID.</exception>
275+
public async Task<UserRecord> GetUserAsync(string uid)
276+
{
277+
return await this.GetUserAsync(uid, default(CancellationToken));
278+
}
279+
280+
/// <summary>
281+
/// Gets a <see cref="UserRecord"/> object containig information about the user who's
282+
/// user ID was specified in <paramref name="uid"/>.
283+
/// </summary>
284+
/// <param name="uid">The user ID for the user who's data is to be retrieved.</param>
285+
/// <param name="cancellationToken">A cancellation token to monitor the asynchronous
286+
/// operation.</param>
287+
/// <returns>A task that completes with a <see cref="UserRecord"/> representing
288+
/// a user with the specified user ID.</returns>
289+
/// <exception cref="ArgumentException">If user ID argument is null or empty.</exception>
290+
/// <exception cref="FirebaseException">If a user cannot be found with the specified user ID.</exception>
291+
public async Task<UserRecord> GetUserAsync(
292+
string uid, CancellationToken cancellationToken)
293+
{
294+
var userManager = this.IfNotDeleted(() => this.userManager.Value);
295+
296+
return await userManager.GetUserById(uid, cancellationToken);
297+
}
298+
266299
/// <summary>
267300
/// Sets the specified custom claims on an existing user account. A null claims value
268301
/// removes any claims currently set on the user account. The claims must serialize into

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseUserManager.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,21 @@ public async Task<UserRecord> GetUserById(
8181
{
8282
{ "localId", uid },
8383
};
84-
var response = await this.PostAndDeserializeAsync<JObject>(
84+
85+
var response = await this.PostAndDeserializeAsync<GetAccountInfoResponse>(
8586
getUserPath, payload, cancellationToken).ConfigureAwait(false);
86-
if (response == null || uid != (string)response["localId"])
87+
if (response == null || response.Users == null || response.Users.Count == 0)
88+
{
89+
throw new FirebaseException($"Failed to get user: {uid}");
90+
}
91+
92+
var user = response.Users[0];
93+
if (user == null || user.UserId != uid)
8794
{
8895
throw new FirebaseException($"Failed to get user: {uid}");
8996
}
9097

91-
return new UserRecord((string)response["localId"]);
98+
return new UserRecord(user);
9299
}
93100

94101
/// <summary>
@@ -102,9 +109,15 @@ public async Task UpdateUserAsync(
102109
UserRecord user, CancellationToken cancellationToken = default(CancellationToken))
103110
{
104111
const string updatePath = "accounts:update";
105-
var response = await this.PostAndDeserializeAsync<JObject>(
112+
var response = await this.PostAndDeserializeAsync<GetAccountInfoResponse>(
106113
updatePath, user, cancellationToken).ConfigureAwait(false);
107-
if (user.Uid != (string)response["localId"])
114+
if (response == null || response.Users == null || response.Users.Count == 0)
115+
{
116+
throw new FirebaseException($"Failed to get user: {user.Uid}");
117+
}
118+
119+
var updatedUser = response.Users[0];
120+
if (updatedUser == null || updatedUser.UserId != user.Uid)
108121
{
109122
throw new FirebaseException($"Failed to update user: {user.Uid}");
110123
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
5+
namespace FirebaseAdmin.Auth
6+
{
7+
/// <summary>
8+
/// A collection of standard profile information for a user. Used to expose profile information
9+
/// returned by an identity provider.
10+
/// </summary>
11+
public interface IUserInfo
12+
{
13+
/// <summary>
14+
/// Gets the user's unique ID assigned by the identity provider.
15+
/// </summary>
16+
/// <returns>a user ID string.</returns>
17+
string Uid
18+
{
19+
get;
20+
}
21+
22+
/// <summary>
23+
/// Gets the user's display name, if available.
24+
/// </summary>
25+
/// <returns>a display name string or null.</returns>
26+
string DisplayName
27+
{
28+
get;
29+
}
30+
31+
/// <summary>
32+
/// Gets the user's email address, if available.
33+
/// </summary>
34+
/// <returns>an email address string or null.</returns>
35+
string Email
36+
{
37+
get;
38+
}
39+
40+
/// <summary>
41+
/// Gets the user's phone number, if available.
42+
/// </summary>
43+
/// <returns>a phone number string or null.</returns>
44+
string PhoneNumber
45+
{
46+
get;
47+
}
48+
49+
/// <summary>
50+
/// Gets the user's photo URL, if available.
51+
/// </summary>
52+
/// <returns>a URL string or null.</returns>
53+
string PhotoUrl
54+
{
55+
get;
56+
}
57+
58+
/// <summary>
59+
/// Gets the ID of the identity provider. This can be a short domain name (e.g. google.com) or
60+
/// the identifier of an OpenID identity provider.
61+
/// </summary>
62+
/// <returns>an ID string that uniquely identifies the identity provider.</returns>
63+
string ProviderId
64+
{
65+
get;
66+
}
67+
}
68+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Text;
4+
using Newtonsoft.Json;
5+
6+
namespace FirebaseAdmin.Auth
7+
{
8+
/// <summary>
9+
/// JSON data binding for GetAccountInfoResponse messages sent by Google identity toolkit service.
10+
/// </summary>
11+
internal sealed class GetAccountInfoResponse
12+
{
13+
/// <summary>
14+
/// Gets or sets a string representing what kind of account is represented by this object.
15+
/// </summary>
16+
[JsonProperty(PropertyName = "kind")]
17+
public string Kind { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets a list of provider users linked to this account.
21+
/// </summary>
22+
[JsonProperty(PropertyName = "users")]
23+
public List<User> Users { get; set; }
24+
25+
/// <summary>
26+
/// JSON data binding for user records.
27+
/// </summary>
28+
internal sealed class User
29+
{
30+
/// <summary>
31+
/// Gets or sets the user's ID.
32+
/// </summary>
33+
[JsonProperty(PropertyName = "localId")]
34+
public string UserId { get; set; }
35+
36+
/// <summary>
37+
/// Gets or sets the user's email address.
38+
/// </summary>
39+
[JsonProperty(PropertyName = "email")]
40+
public string Email { get; set; }
41+
42+
/// <summary>
43+
/// Gets or sets the user's phone number.
44+
/// </summary>
45+
[JsonProperty(PropertyName = "phoneNumber")]
46+
public string PhoneNumber { get; set; }
47+
48+
/// <summary>
49+
/// Gets or sets a value indicating whether the user's email address is verified or not.
50+
/// </summary>
51+
[JsonProperty(PropertyName = "emailVerified")]
52+
public bool EmailVerified { get; set; }
53+
54+
/// <summary>
55+
/// Gets or sets the user's display name.
56+
/// </summary>
57+
[JsonProperty(PropertyName = "displayName")]
58+
public string DisplayName { get; set; }
59+
60+
/// <summary>
61+
/// Gets or sets the URL for the user's photo.
62+
/// </summary>
63+
[JsonProperty(PropertyName = "photoUrl")]
64+
public string PhotoUrl { get; set; }
65+
66+
/// <summary>
67+
/// Gets or sets a value indicating whether the user is disabled or not.
68+
/// </summary>
69+
[JsonProperty(PropertyName = "disabled")]
70+
public bool Disabled { get; set; }
71+
72+
/// <summary>
73+
/// Gets or sets a list of provider-specified data for this user.
74+
/// </summary>
75+
[JsonProperty(PropertyName = "providerUserInfo")]
76+
public List<Provider> Providers { get; set; }
77+
78+
/// <summary>
79+
/// Gets or sets the timestamp representing the time that the user account was created.
80+
/// </summary>
81+
[JsonProperty(PropertyName = "createdAt")]
82+
public long CreatedAt { get; set; }
83+
84+
/// <summary>
85+
/// Gets or sets the timestamp representing the last time that the user has logged in.
86+
/// </summary>
87+
[JsonProperty(PropertyName = "lastLoginAt")]
88+
public long LastLoginAt { get; set; }
89+
90+
/// <summary>
91+
/// Gets or sets the timestamp representing the time that the user account was first valid.
92+
/// </summary>
93+
[JsonProperty(PropertyName = "validSince")]
94+
public long ValidSince { get; set; }
95+
96+
/// <summary>
97+
/// Gets or sets the user's custom claims.
98+
/// </summary>
99+
[JsonProperty(PropertyName = "customAttributes")]
100+
public string CustomClaims { get; set; }
101+
}
102+
103+
/// <summary>
104+
/// JSON data binding for provider data.
105+
/// </summary>
106+
internal sealed class Provider
107+
{
108+
/// <summary>
109+
/// Gets or sets the user's ID.
110+
/// </summary>
111+
[JsonProperty(PropertyName = "uid")]
112+
public string UserId { get; set; }
113+
114+
/// <summary>
115+
/// Gets or sets the user's display name.
116+
/// </summary>
117+
[JsonProperty(PropertyName = "displayName")]
118+
public string DisplayName { get; set; }
119+
120+
/// <summary>
121+
/// Gets or sets the user's email address.
122+
/// </summary>
123+
[JsonProperty(PropertyName = "email")]
124+
public string Email { get; set; }
125+
126+
/// <summary>
127+
/// Gets or sets the user's phone number.
128+
/// </summary>
129+
[JsonProperty(PropertyName = "phoneNumber")]
130+
public string PhoneNumber { get; set; }
131+
132+
/// <summary>
133+
/// Gets or sets the URL for the user's photo.
134+
/// </summary>
135+
[JsonProperty(PropertyName = "photoUrl")]
136+
public string PhotoUrl { get; set; }
137+
138+
/// <summary>
139+
/// Gets or sets the provider's ID.
140+
/// </summary>
141+
[JsonProperty(PropertyName = "providerId")]
142+
public string ProviderID { get; set; }
143+
}
144+
}
145+
}

0 commit comments

Comments
 (0)