Skip to content

Commit

Permalink
Added endpoint to get list of Zoom Phone users (#344)
Browse files Browse the repository at this point in the history
* Get list of Phone users endpoint is added

* Fix: set missing default value for pageSize and added a check for the value to be in available range; added unit test

* Changed type of get phone users endpoint response

* Added new model 'PhoneUser' and reused it in Phone.ListPhoneUsers resource instead of 'PhoneCallUserProfile' model

---------

Co-authored-by: Snezhanna Roshchupkina <Snezhanna.Roshchupkina@lanit-tercom.com>
  • Loading branch information
snega1003 and sroshchupkina committed Apr 26, 2024
1 parent 9389bc5 commit 4d586b5
Show file tree
Hide file tree
Showing 8 changed files with 367 additions and 1 deletion.
84 changes: 84 additions & 0 deletions Source/ZoomNet.UnitTests/Models/PhoneUserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Text.Json;
using Shouldly;
using Xunit;
using ZoomNet.Json;
using ZoomNet.Models;

namespace ZoomNet.UnitTests.Models
{
public class PhoneUserTests
{
#region constants

internal const string PHONE_USER = @"{
""id"": ""NL3cEpSdRc-c2t8aLoZqiw"",
""phone_user_id"": ""u7pnC468TaS46OuNoEw6GA"",
""email"": ""test_phone_user@testapi.com"",
""name"": ""test phone user"",
""extension_id"": ""CcrEGgmeQem1uyJsuIRKwA"",
""extension_number"": 123,
""status"": ""activate"",
""calling_plans"": [
{
""type"": 600,
""name"": ""Delhi billing"",
""billing_account_id"": ""3WWAEiEjTj2IQuyDiKMd_A"",
""billing_account_name"": ""Delhi billing""
}
],
""phone_numbers"": [
{
""id"": ""---M1padRvSUtw7YihN7sA"",
""number"": ""14232058798""
}
],
""site"": {
""id"": ""8f71O6rWT8KFUGQmJIFAdQ"",
""name"": ""Test Site""
},
""department"": ""Test"",
""cost_center"": ""Cost Test Center""
}";

#endregion

#region tests

[Fact]
public void Parse_Json_PhoneUserTests()
{
// Arrange

// Act
var result = JsonSerializer.Deserialize<PhoneUser>(
PHONE_USER, JsonFormatter.SerializerOptions);

// Assert
result.Id.ShouldBe("NL3cEpSdRc-c2t8aLoZqiw");
result.PhoneUserId.ShouldBe("u7pnC468TaS46OuNoEw6GA");
result.Email.ShouldBe("test_phone_user@testapi.com");
result.Name.ShouldBe("test phone user");
result.ExtensionId.ShouldBe("CcrEGgmeQem1uyJsuIRKwA");
result.ExtensionNumber.ShouldBe(123);
result.Status.ShouldBe(PhoneCallUserStatus.Active);
result.CallingPlans.ShouldNotBeNull();
result.CallingPlans.Length.ShouldBe(1);
result.PhoneNumbers.ShouldNotBeNull();
result.PhoneNumbers.Length.ShouldBe(1);
result.Department.ShouldBe("Test");
result.CostCenter.ShouldBe("Cost Test Center");
result.Site.Id.ShouldBe("8f71O6rWT8KFUGQmJIFAdQ");
result.Site.Name.ShouldBe("Test Site");

var callingPlan = result.CallingPlans[0];
callingPlan.BillingAccountId.ShouldBe("3WWAEiEjTj2IQuyDiKMd_A");
callingPlan.BillingAccountName.ShouldBe("Delhi billing");

var phoneNumber = result.PhoneNumbers[0];
phoneNumber.PhoneNumberId.ShouldBe("---M1padRvSUtw7YihN7sA");
phoneNumber.PhoneNumber.ShouldBe("14232058798");
}

#endregion
}
}
114 changes: 114 additions & 0 deletions Source/ZoomNet.UnitTests/Resources/PhoneUserTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using System;
using System.Net.Http;
using System.Threading.Tasks;
using RichardSzalay.MockHttp;
using Shouldly;
using Xunit;
using ZoomNet.Resources;

namespace ZoomNet.UnitTests.Resources
{
public class PhoneUserTests
{
#region constants

internal const string PHONE_USERS_PAGINATED_OBJECT = @"{
""next_page_token"": ""F2qwertyg5eIqRRgC2YMauur8ZHUaJqtS3i"",
""page_size"": 1,
""total_records"": 10,
""users"": [
{
""id"": ""NL3cEpSdRc-c2t8aLoZqiw"",
""phone_user_id"": ""u7pnC468TaS46OuNoEw6GA"",
""email"": ""test_phone_user@testapi.com"",
""name"": ""test phone user"",
""extension_id"": ""CcrEGgmeQem1uyJsuIRKwA"",
""extension_number"": 123,
""status"": ""activate"",
""calling_plans"": [
{
""type"": 600,
""name"": ""Delhi billing"",
""billing_account_id"": ""3WWAEiEjTj2IQuyDiKMd_A"",
""billing_account_name"": ""Delhi billing""
}
],
""phone_numbers"": [
{
""id"": ""---M1padRvSUtw7YihN7sA"",
""number"": ""14232058798""
}
],
""site"": {
""id"": ""8f71O6rWT8KFUGQmJIFAdQ"",
""name"": ""Test Site""
},
""department"": ""Test"",
""cost_center"": ""Cost Test Center""
}
]
}";

#endregion

#region tests

[Fact]
public async Task GetPhoneUsersPaginatedResponseTestsAsync()
{
// Arrange
var pageSize = 1;

var mockHttp = new MockHttpMessageHandler();
mockHttp
.Expect(
HttpMethod.Get,
Utils.GetZoomApiUri("phone/users"))
.Respond(
"application/json",
PHONE_USERS_PAGINATED_OBJECT);

var client = Utils.GetFluentClient(mockHttp);
var phone = new Phone(client);

// Act
var result = await phone
.ListPhoneUsersAsync(pageSize: pageSize)
.ConfigureAwait(true);

// Assert
mockHttp.VerifyNoOutstandingExpectation();
mockHttp.VerifyNoOutstandingRequest();
result.NextPageToken.ShouldNotBeNullOrEmpty();
result.PageSize.ShouldBe(1);
result.TotalRecords.ShouldBe(10);
result.Records.ShouldNotBeNull();
result.Records.Length.ShouldBe(1);
result.Records[0].Id.ShouldBe("NL3cEpSdRc-c2t8aLoZqiw");
result.Records[0].PhoneNumbers[0].PhoneNumberId.ShouldBe("---M1padRvSUtw7YihN7sA");
result.Records[0].PhoneNumbers[0].PhoneNumber.ShouldBe("14232058798");
}

[Theory]
[InlineData(0)]
[InlineData(101)]
public void InvalidPageSize_GetPhoneUsersPaginatedResponseTests(int pageSize)
{
// Arrange
var mockHttp = new MockHttpMessageHandler();

var client = Utils.GetFluentClient(mockHttp);
var phone = new Phone(client);

// Act and Assert
var exception = Assert.Throws<ArgumentOutOfRangeException>(() => phone
.ListPhoneUsersAsync(pageSize: pageSize)
.ConfigureAwait(true));

exception.ParamName.ShouldBe(nameof(pageSize));
exception.Message.ShouldBe($"Records per page must be between 1 and 100 (Parameter '{nameof(pageSize)}')");
}

#endregion
}
}
4 changes: 4 additions & 0 deletions Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.PhoneCallUserStatus))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneNumber))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneType))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneUser))]
[JsonSerializable(typeof(ZoomNet.Models.PmiMeetingPasswordRequirementType))]
[JsonSerializable(typeof(ZoomNet.Models.Poll))]
[JsonSerializable(typeof(ZoomNet.Models.PollAnswer))]
Expand Down Expand Up @@ -208,6 +209,7 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.ScreenshareDetails))]
[JsonSerializable(typeof(ZoomNet.Models.SecuritySettings))]
[JsonSerializable(typeof(ZoomNet.Models.SharingAndRecordingDetail))]
[JsonSerializable(typeof(ZoomNet.Models.Site))]
[JsonSerializable(typeof(ZoomNet.Models.SmsAttachment))]
[JsonSerializable(typeof(ZoomNet.Models.SmsAttachmentType))]
[JsonSerializable(typeof(ZoomNet.Models.SmsDirection))]
Expand Down Expand Up @@ -448,6 +450,7 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.PhoneCallUserStatus[]))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneNumber[]))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneType[]))]
[JsonSerializable(typeof(ZoomNet.Models.PhoneUser[]))]
[JsonSerializable(typeof(ZoomNet.Models.PmiMeetingPasswordRequirementType[]))]
[JsonSerializable(typeof(ZoomNet.Models.Poll[]))]
[JsonSerializable(typeof(ZoomNet.Models.PollAnswer[]))]
Expand Down Expand Up @@ -504,6 +507,7 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.ScreenshareDetails[]))]
[JsonSerializable(typeof(ZoomNet.Models.SecuritySettings[]))]
[JsonSerializable(typeof(ZoomNet.Models.SharingAndRecordingDetail[]))]
[JsonSerializable(typeof(ZoomNet.Models.Site[]))]
[JsonSerializable(typeof(ZoomNet.Models.SmsAttachment[]))]
[JsonSerializable(typeof(ZoomNet.Models.SmsAttachmentType[]))]
[JsonSerializable(typeof(ZoomNet.Models.SmsDirection[]))]
Expand Down
2 changes: 1 addition & 1 deletion Source/ZoomNet/Models/PhoneCallUserProfile.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Text.Json.Serialization;
using System.Text.Json.Serialization;

namespace ZoomNet.Models;

Expand Down
81 changes: 81 additions & 0 deletions Source/ZoomNet/Models/PhoneUser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using System.Text.Json.Serialization;

namespace ZoomNet.Models;

/// <summary>
/// Zoom Phone user information.
/// </summary>
public class PhoneUser
{
/// <summary>
/// Gets or sets the calling plans.
/// </summary>
[JsonPropertyName("calling_plans")]
public CallingPlan[] CallingPlans { get; set; }

/// <summary>
/// Gets or sets the cost center.
/// </summary>
[JsonPropertyName("cost_center")]
public string CostCenter { get; set; }

/// <summary>
/// Gets or sets the department of the object.
/// </summary>
[JsonPropertyName("department")]
public string Department { get; set; }

/// <summary>
/// Gets or sets the email address.
/// </summary>
[JsonPropertyName("email")]
public string Email { get; set; }

/// <summary>
/// Gets or sets the extension ID.
/// </summary>
[JsonPropertyName("extension_id")]
public string ExtensionId { get; set; }

/// <summary>
/// Gets or sets the extension number.
/// </summary>
[JsonPropertyName("extension_number")]
public int ExtensionNumber { get; set; }

/// <summary>
/// Gets or sets the Zoom user ID.
/// </summary>
[JsonPropertyName("id")]
public string Id { get; set; }

/// <summary>
/// Gets or sets the Zoom user name.
/// </summary>
[JsonPropertyName("name")]
public string Name { get; set; }

/// <summary>
/// Gets or sets the phone numbers.
/// </summary>
[JsonPropertyName("phone_numbers")]
public PhoneCallPhoneNumber[] PhoneNumbers { get; set; }

/// <summary>
/// Gets or sets the Zoom phone user id.
/// </summary>
[JsonPropertyName("phone_user_id")]
public string PhoneUserId { get; set; }

/// <summary>
/// Gets or sets a site.
/// </summary>
[JsonPropertyName("site")]
public Site Site { get; set; }

/// <summary>
/// Gets or sets the status of the user.
/// </summary>
[JsonPropertyName("status")]
public PhoneCallUserStatus Status { get; set; }
}
21 changes: 21 additions & 0 deletions Source/ZoomNet/Models/Site.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Text.Json.Serialization;

namespace ZoomNet.Models;

/// <summary>
/// Site information to which a user belongs to.
/// </summary>
public class Site
{
/// <summary>
/// Gets or sets the Id.
/// </summary>
[JsonPropertyName("id")]
public string Id { get; set; }

/// <summary>
/// Gets or sets the name.
/// </summary>
[JsonPropertyName("name")]
public string Name { get; set; }
}
30 changes: 30 additions & 0 deletions Source/ZoomNet/Resources/IPhone.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,36 @@ public interface IPhone
Task<PhoneCallUserProfile> GetPhoneCallUserProfileAsync(
string userId, CancellationToken cancellationToken = default);

/// <summary>
/// Retrieves a list of all of an account's users who are assigned a Zoom Phone license.
/// </summary>
/// <param name="pageSize">The number of records returned from a single API call. Default is 30.</param>
/// <param name="nextPageToken">
/// The next page token paginates through a large set of results.
/// A next page token is returned whenever the set of available results exceeds the current page size.
/// The expiration period for this token is 15 minutes.
/// </param>
/// <param name="siteId">The unique identifier of the site.</param>
/// <param name="callingType">The type of calling plan.</param>
/// <param name="status">The status of the Zoom Phone user.</param>
/// <param name="department">The department where the user belongs.</param>
/// <param name="costCenter">The cost center where the user belongs.</param>
/// <param name="keyword">The partial string of user's name, extension number, or phone number.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
/// <returns>
/// A task representing the asynchronous operation. The task result contains an array of Zoom Phone users in type of <see cref="PhoneUser"/>.
/// </returns>
Task<PaginatedResponseWithToken<PhoneUser>> ListPhoneUsersAsync(
int pageSize = 30,
string nextPageToken = null,
string siteId = null,
int? callingType = null,
PhoneCallUserStatus? status = null,
string department = null,
string costCenter = null,
string keyword = null,
CancellationToken cancellationToken = default);

#endregion
}
}

0 comments on commit 4d586b5

Please sign in to comment.