Skip to content

Commit a013359

Browse files
committed
Merged with master
2 parents c5738a8 + 75b86e1 commit a013359

24 files changed

+726
-22
lines changed

CHANGELOG.md

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

3+
- [added] Implemented the `UpdateUserAsync()` API.
34
- [added] Implemented the `CreateUserAsync()` and `UserRecordArgs` APIs.
5+
6+
# v1.6.0
7+
8+
- [added] `WebpushFcmOptions` added to the `WebpushConfig` class.
49
- [added] Implemented the `GetUserByEmailAsync()` and `GetUserByPhoneNumberAsync()`
510
APIs in the `FirebaseAuth` class.
611

FirebaseAdmin/FirebaseAdmin.IntegrationTests/FirebaseAdmin.IntegrationTests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Google.Apis.Auth" Version="1.35.1" />
11+
<PackageReference Include="Google.Apis.Auth" Version="1.40.0" />
1212
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
1313
<PackageReference Include="xunit" Version="2.3.1" />
1414
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

FirebaseAdmin/FirebaseAdmin.Snippets/FirebaseAdmin.Snippets.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
</PropertyGroup>
99

1010
<ItemGroup>
11-
<PackageReference Include="Google.Apis.Auth" Version="1.35.1" />
11+
<PackageReference Include="Google.Apis.Auth" Version="1.40.0" />
1212
</ItemGroup>
1313

1414
<ItemGroup>

FirebaseAdmin/FirebaseAdmin.Tests/Auth/FirebaseUserManagerTest.cs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,13 @@
1414

1515
using System;
1616
using System.Collections.Generic;
17+
using System.Linq;
1718
using System.Net;
1819
using System.Net.Http;
1920
using System.Threading.Tasks;
2021
using FirebaseAdmin.Tests;
22+
using Google.Api.Gax;
23+
using Google.Api.Gax.Rest;
2124
using Google.Apis.Auth.OAuth2;
2225
using Google.Apis.Json;
2326
using Newtonsoft.Json.Linq;
@@ -285,6 +288,90 @@ public async Task GetUserByPhoneNumberEmpty()
285288
await Assert.ThrowsAsync<ArgumentException>(() => auth.GetUserByPhoneNumberAsync(string.Empty));
286289
}
287290

291+
[Fact]
292+
public async Task ListUsersPaged()
293+
{
294+
var handler = new MockMessageHandler()
295+
{
296+
Response = new List<string>()
297+
{
298+
@"{
299+
""nextPageToken"": ""token"",
300+
""users"": [
301+
{""localId"": ""user1""},
302+
{""localId"": ""user2""},
303+
{""localId"": ""user3""}
304+
]
305+
}",
306+
@"{
307+
""users"": [
308+
{""localId"": ""user4""},
309+
{""localId"": ""user5""},
310+
{""localId"": ""user6""}
311+
]
312+
}",
313+
},
314+
};
315+
var auth = this.CreateFirebaseAuth(handler);
316+
317+
var usersPage = auth.ListUsersAsync(new ListUsersOptions());
318+
319+
var users = new List<ExportedUserRecord>();
320+
var tokens = new List<string>();
321+
var pageCounter = 0;
322+
for (Page<ExportedUserRecord> userPage; (userPage = await usersPage.ReadPageAsync(3)) != null;)
323+
{
324+
pageCounter++;
325+
tokens.Add(userPage.NextPageToken);
326+
users.AddRange(userPage);
327+
if (string.IsNullOrEmpty(userPage.NextPageToken))
328+
{
329+
break;
330+
}
331+
}
332+
333+
Assert.Equal(2, pageCounter);
334+
Assert.Equal(6, users.Count);
335+
Assert.Equal("token", tokens[0]);
336+
Assert.Null(tokens[1]);
337+
Assert.Equal("user1", users[0].Uid);
338+
Assert.Equal("user2", users[1].Uid);
339+
Assert.Equal("user3", users[2].Uid);
340+
Assert.Equal("user4", users[3].Uid);
341+
Assert.Equal("user5", users[4].Uid);
342+
Assert.Equal("user6", users[5].Uid);
343+
}
344+
345+
[Fact]
346+
public async Task ListUsers()
347+
{
348+
var nextPageToken = Guid.NewGuid().ToString();
349+
var handler = new MockMessageHandler()
350+
{
351+
Response = new DownloadAccountResponse()
352+
{
353+
NextPageToken = nextPageToken,
354+
Users = new List<GetAccountInfoResponse.User>()
355+
{
356+
new GetAccountInfoResponse.User() { UserId = "user1" },
357+
new GetAccountInfoResponse.User() { UserId = "user2" },
358+
new GetAccountInfoResponse.User() { UserId = "user3" },
359+
},
360+
},
361+
};
362+
363+
var auth = this.CreateFirebaseAuth(handler);
364+
365+
var usersPage = auth.ListUsersAsync(new ListUsersOptions());
366+
var listUsersRequest = await usersPage.ReadPageAsync(3);
367+
var userRecords = listUsersRequest.ToList();
368+
Assert.Equal(nextPageToken, listUsersRequest.NextPageToken);
369+
Assert.Equal(3, userRecords.Count);
370+
Assert.Equal("user1", userRecords[0].Uid);
371+
Assert.Equal("user2", userRecords[1].Uid);
372+
Assert.Equal("user3", userRecords[2].Uid);
373+
}
374+
288375
[Fact]
289376
public async Task CreateUser()
290377
{

FirebaseAdmin/FirebaseAdmin.Tests/FirebaseAdmin.Tests.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
</PropertyGroup>
1111

1212
<ItemGroup>
13-
<PackageReference Include="Google.Apis.Auth" Version="1.35.1" />
13+
<PackageReference Include="Google.Apis.Auth" Version="1.40.0" />
1414
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
1515
<PackageReference Include="xunit" Version="2.3.1" />
1616
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />

FirebaseAdmin/FirebaseAdmin.Tests/Messaging/MessageTest.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1558,6 +1558,98 @@ public void ApnsInvalidCriticalSoundVolumeTooHigh()
15581558
Assert.Throws<ArgumentException>(() => message.CopyAndValidate());
15591559
}
15601560

1561+
[Fact]
1562+
public void WebpushNotificationWithLinkUrl()
1563+
{
1564+
var message = new Message()
1565+
{
1566+
Topic = "test-topic",
1567+
Webpush = new WebpushConfig()
1568+
{
1569+
Notification = new WebpushNotification()
1570+
{
1571+
Title = "title",
1572+
Body = "body",
1573+
Icon = "icon",
1574+
},
1575+
FcmOptions = new WebpushFcmOptions()
1576+
{
1577+
Link = "https://www.firebase.io/",
1578+
},
1579+
},
1580+
};
1581+
var expected = new JObject()
1582+
{
1583+
{ "topic", "test-topic" },
1584+
{
1585+
"webpush", new JObject()
1586+
{
1587+
{
1588+
"notification", new JObject()
1589+
{
1590+
{ "title", "title" },
1591+
{ "body", "body" },
1592+
{ "icon", "icon" },
1593+
}
1594+
},
1595+
{
1596+
"fcm_options", new JObject()
1597+
{
1598+
{ "link", "https://www.firebase.io/" },
1599+
}
1600+
},
1601+
}
1602+
},
1603+
};
1604+
this.AssertJsonEquals(expected, message);
1605+
}
1606+
1607+
[Fact]
1608+
public void WebpushNotificationWithInvalidHttpLinkUrl()
1609+
{
1610+
var message = new Message()
1611+
{
1612+
Topic = "test-topic",
1613+
Webpush = new WebpushConfig()
1614+
{
1615+
Notification = new WebpushNotification()
1616+
{
1617+
Title = "title",
1618+
Body = "body",
1619+
Icon = "icon",
1620+
},
1621+
FcmOptions = new WebpushFcmOptions()
1622+
{
1623+
Link = "http://www.firebase.io/",
1624+
},
1625+
},
1626+
};
1627+
Assert.Throws<ArgumentException>(() => message.CopyAndValidate());
1628+
}
1629+
1630+
[Fact]
1631+
public void WebpushNotificationWithInvalidHttpsLinkUrl()
1632+
{
1633+
var message = new Message()
1634+
{
1635+
Topic = "test-topic",
1636+
Webpush = new WebpushConfig()
1637+
{
1638+
Notification = new WebpushNotification()
1639+
{
1640+
Title = "title",
1641+
Body = "body",
1642+
Icon = "icon",
1643+
},
1644+
FcmOptions = new WebpushFcmOptions()
1645+
{
1646+
Link = "https whatever",
1647+
},
1648+
},
1649+
};
1650+
Assert.Throws<ArgumentException>(() => message.CopyAndValidate());
1651+
}
1652+
15611653
private void AssertJsonEquals(JObject expected, Message actual)
15621654
{
15631655
var json = NewtonsoftJsonSerializer.Instance.Serialize(actual.CopyAndValidate());
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2019, Google Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
namespace FirebaseAdmin.Auth
16+
{
17+
/// <summary>
18+
/// Contains metadata associated with a Firebase user account, along with password hash and salt.
19+
/// Instances of this class are immutable and thread safe.
20+
/// </summary>
21+
public sealed class ExportedUserRecord : UserRecord
22+
{
23+
private readonly string passwordHash;
24+
private readonly string passwordSalt;
25+
26+
internal ExportedUserRecord(GetAccountInfoResponse.User user)
27+
: base(user)
28+
{
29+
this.passwordHash = user.PasswordHash;
30+
this.passwordSalt = user.PasswordSalt;
31+
}
32+
33+
/// <summary>
34+
/// Gets the user's password hash as a base64-encoded string.
35+
/// If the Firebase Auth hashing algorithm (SCRYPT) was used to create the user account,
36+
/// returns the base64-encoded password hash of the user.If a different hashing algorithm was
37+
/// used to create this user, as is typical when migrating from another Auth system, returns
38+
/// an empty string. Returns null if no password is set.
39+
/// </summary>
40+
public string PasswordHash
41+
{
42+
get => this.passwordHash;
43+
}
44+
45+
/// <summary>
46+
/// Gets the user's password salt as a base64-encoded string.
47+
/// If the Firebase Auth hashing algorithm (SCRYPT) was used to create the user account,
48+
/// returns the base64-encoded password salt of the user.If a different hashing algorithm was
49+
/// used to create this user, as is typical when migrating from another Auth system, returns
50+
/// an empty string. Returns null if no password is set.
51+
/// </summary>
52+
public string PasswordSalt
53+
{
54+
get => this.passwordSalt;
55+
}
56+
}
57+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// Copyright 2019, Google Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System.Collections.Generic;
16+
17+
namespace FirebaseAdmin.Auth
18+
{
19+
/// <summary>
20+
/// Contains a collection of Firebase user accounts.
21+
/// </summary>
22+
public sealed class ExportedUserRecords
23+
{
24+
/// <summary>
25+
/// Gets or sets the next page link.
26+
/// </summary>
27+
public string NextPageToken { get; set; }
28+
29+
/// <summary>
30+
/// Gets or sets the users.
31+
/// </summary>
32+
public List<ExportedUserRecord> Users { get; set; }
33+
}
34+
}

FirebaseAdmin/FirebaseAdmin/Auth/FirebaseAuth.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using System.Collections.Generic;
1717
using System.Threading;
1818
using System.Threading.Tasks;
19+
using Google.Api.Gax;
1920
using Google.Apis.Util;
2021

2122
namespace FirebaseAdmin.Auth
@@ -520,6 +521,18 @@ public async Task SetCustomUserClaimsAsync(
520521
await userManager.UpdateUserAsync(user, cancellationToken).ConfigureAwait(false);
521522
}
522523

524+
/// <summary>
525+
/// Gets an async enumerable to page users starting from the specified pageToken. If the pageToken is empty, it starts from the first page.
526+
/// </summary>
527+
/// <param name="requestOptions">The options for the next remote call.</param>
528+
/// <returns>A <see cref="PagedAsyncEnumerable{DownloadAccountResponse, UserRecord}"/> instance.</returns>
529+
public PagedAsyncEnumerable<ExportedUserRecords, ExportedUserRecord> ListUsersAsync(ListUsersOptions requestOptions)
530+
{
531+
var userManager = this.IfNotDeleted(() => this.userManager.Value);
532+
533+
return userManager.ListUsers(requestOptions);
534+
}
535+
523536
/// <summary>
524537
/// Deletes this <see cref="FirebaseAuth"/> service instance.
525538
/// </summary>

0 commit comments

Comments
 (0)