Skip to content

Commit

Permalink
Merge branch 'release/0.87.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
Jericho committed Jan 14, 2025
2 parents 59f0341 + 6e84d9c commit c4c4241
Show file tree
Hide file tree
Showing 16 changed files with 301 additions and 43 deletions.
1 change: 0 additions & 1 deletion Source/ZoomNet.IntegrationTests/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ private static void ConfigureServices(ServiceCollection services)
{
services.AddHostedService<TestsRunner>();


services
.AddLogging(logging =>
{
Expand Down
1 change: 1 addition & 0 deletions Source/ZoomNet.IntegrationTests/TestSuites/ApiTestSuite.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ internal class ApiTestSuite : TestSuite
typeof(CloudRecordings),
typeof(Contacts),
typeof(Dashboards),
typeof(ExternalContacts),
typeof(Meetings),
typeof(Reports),
typeof(Roles),
Expand Down
21 changes: 21 additions & 0 deletions Source/ZoomNet.IntegrationTests/Tests/ExternalContacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using ZoomNet.Models;

namespace ZoomNet.IntegrationTests.Tests
{
public class ExternalContacts : IIntegrationTest
{
public async Task RunAsync(User myUser, string[] myPermissions, IZoomClient client, TextWriter log, CancellationToken cancellationToken)
{
if (cancellationToken.IsCancellationRequested) return;

await log.WriteLineAsync("\n***** EXTERNAL CONTACTS *****\n").ConfigureAwait(false);

// GET ALL THE EXTERNAL CONTACTS
var paginatedContacts = await client.ExternalContacts.GetAllAsync(100, null, cancellationToken).ConfigureAwait(false);
await log.WriteLineAsync($"There are {paginatedContacts.TotalRecords} external contacts under the main account").ConfigureAwait(false);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Formitable.BetterStack.Logger.Microsoft" Version="0.1.2" />
<PackageReference Include="Formitable.BetterStack.Logger.Microsoft" Version="0.1.3-beta0001" />
<PackageReference Include="Microsoft.Extensions.Diagnostics" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.0" />
</ItemGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ public void Write_multiple()
[InlineData("win 11", ParticipantDevice.Windows)]
[InlineData("Zoom Rooms", ParticipantDevice.ZoomRoom)]
[InlineData("win 10+ 17763", ParticipantDevice.Windows)]
[InlineData("Web Browser", ParticipantDevice.Web)]
[InlineData("Web Browser Chrome 129", ParticipantDevice.Web)]
[InlineData("Web Browser Chrome 130", ParticipantDevice.Web)]
[InlineData("Windows 10", ParticipantDevice.Windows)]
Expand Down
9 changes: 5 additions & 4 deletions Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,21 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="coverlet.msbuild" Version="6.0.2">
<PackageReference Include="coverlet.msbuild" Version="6.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="9.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageReference Include="NSubstitute" Version="5.3.0" />
<PackageReference Include="NSubstitute.Analyzers.CSharp" Version="1.0.17">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="RichardSzalay.MockHttp" Version="7.0.0" />
<PackageReference Include="Shouldly" Version="4.2.1" />
<PackageReference Include="xunit" Version="2.9.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.8.2">
<PackageReference Include="xunit" Version="2.9.3" />
<PackageReference Include="xunit.runner.visualstudio" Version="3.0.1">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
Expand Down
5 changes: 5 additions & 0 deletions Source/ZoomNet/IZoomClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ public interface IZoomClient
[Obsolete("The Data Compliance API is deprecated")]
IDataCompliance DataCompliance { get; }

/// <summary>
/// Gets the resource which allows you to handle Zoom phone external contacts.
/// </summary>
IExternalContacts ExternalContacts { get; }

/// <summary>
/// Gets the resource that allows you to manage groups.
/// </summary>
Expand Down
6 changes: 4 additions & 2 deletions Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursChildSubsettings), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursChildSubsettings")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursSubsettings), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursSubsettings")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursType), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursType")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.ExternalContact), TypeInfoPropertyName = "CallHandlingSettingsExternalContact")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.HolidaySubsettings), TypeInfoPropertyName = "CallHandlingSettingsHolidaySubsettings")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.RingModeType), TypeInfoPropertyName = "CallHandlingSettingsRingModeType")]
[JsonSerializable(typeof(ZoomNet.Models.CallingPlan))]
Expand Down Expand Up @@ -113,6 +112,8 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.EmailNotificationUserSettings))]
[JsonSerializable(typeof(ZoomNet.Models.EmergencyAddress))]
[JsonSerializable(typeof(ZoomNet.Models.EncryptionType))]
[JsonSerializable(typeof(ZoomNet.Models.ExternalContact))]
[JsonSerializable(typeof(ZoomNet.Models.ExternalContactDetails))]
[JsonSerializable(typeof(ZoomNet.Models.FeatureUserSettings))]
[JsonSerializable(typeof(ZoomNet.Models.ImMetric))]
[JsonSerializable(typeof(ZoomNet.Models.InstantMeeting))]
Expand Down Expand Up @@ -353,7 +354,6 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursChildSubsettings[]), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursChildSubsettingsArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursSubsettings[]), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursSubsettingsArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.CustomHoursType[]), TypeInfoPropertyName = "CallHandlingSettingsCustomHoursTypeArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.ExternalContact[]), TypeInfoPropertyName = "CallHandlingSettingsExternalContactArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.HolidaySubsettings[]), TypeInfoPropertyName = "CallHandlingSettingsHolidaySubsettingsArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallHandlingSettings.RingModeType[]), TypeInfoPropertyName = "CallHandlingSettingsRingModeTypeArray")]
[JsonSerializable(typeof(ZoomNet.Models.CallingPlan[]))]
Expand Down Expand Up @@ -432,6 +432,8 @@ namespace ZoomNet.Json
[JsonSerializable(typeof(ZoomNet.Models.EmailNotificationUserSettings[]))]
[JsonSerializable(typeof(ZoomNet.Models.EmergencyAddress[]))]
[JsonSerializable(typeof(ZoomNet.Models.EncryptionType[]))]
[JsonSerializable(typeof(ZoomNet.Models.ExternalContact[]))]
[JsonSerializable(typeof(ZoomNet.Models.ExternalContactDetails[]))]
[JsonSerializable(typeof(ZoomNet.Models.FeatureUserSettings[]))]
[JsonSerializable(typeof(ZoomNet.Models.ImMetric[]))]
[JsonSerializable(typeof(ZoomNet.Models.InstantMeeting[]))]
Expand Down
16 changes: 0 additions & 16 deletions Source/ZoomNet/Models/CallHandlingSettings/ExternalContact.cs

This file was deleted.

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

namespace ZoomNet.Models
{
/// <summary>
/// Zoom phone external contact model.
/// </summary>
public class ExternalContact
{
/// <summary>
/// Gets or sets the Zoom-generated external contact Id.
/// Don't set it on external contact creation, it will be generated automatically.
/// </summary>
[JsonPropertyName("external_contact_id")]
public string ExternalContactId { get; set; }

/// <summary>
/// Gets or sets the external contact's username or extension display name.
/// </summary>
[JsonPropertyName("name")]
public string Name { get; set; }
}
}
54 changes: 54 additions & 0 deletions Source/ZoomNet/Models/ExternalContactDetails.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;

namespace ZoomNet.Models
{
/// <summary>
/// Zoom phone external contact details model.
/// </summary>
public class ExternalContactDetails : ExternalContact
{
/// <summary>
/// Gets or sets the external contact's description.
/// </summary>
[JsonPropertyName("description")]
public string Description { get; set; }

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

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

/// <summary>
/// Gets or sets the customer-configured external contact ID.
/// If it is not set id will be generated automatically.
/// </summary>
[JsonPropertyName("id")]
public string Id { get; set; }

/// <summary>
/// Gets or sets the external contact's phone numbers.
/// </summary>
[JsonPropertyName("phone_numbers")]
public List<string> PhoneNumbers { get; set; }

/// <summary>
/// Gets or sets the external contact's SIP group, to define the call routing path. This is for customers that use SIP trunking.
/// </summary>
[JsonPropertyName("routing_path")]
public string RoutingPath { get; set; }

/// <summary>
/// Gets or sets a value indicating whether to allow the automatic call recording.
/// </summary>
[JsonPropertyName("auto_call_recorded")]
public bool AutoCallRecorded { get; set; }
}
}
98 changes: 98 additions & 0 deletions Source/ZoomNet/Resources/ExternalContacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
using Pathoschild.Http.Client;
using System;
using System.Threading;
using System.Threading.Tasks;
using ZoomNet;
using ZoomNet.Models;

namespace ZoomNet.Resources
{
/// <inheritdoc/>
public class ExternalContacts : IExternalContacts
{
private readonly IClient _client;

/// <summary>
/// Initializes a new instance of the <see cref="ExternalContacts" /> class.
/// </summary>
/// <param name="client">The HTTP client.</param>
internal ExternalContacts(IClient client)
{
_client = client;
}

/// <inheritdoc/>
public Task<PaginatedResponseWithToken<ExternalContactDetails>> GetAllAsync(int pageSize = 30, string nextPageToken = null, CancellationToken cancellationToken = default)
{
if (pageSize < 1 || pageSize > 300)
{
throw new ArgumentOutOfRangeException(nameof(pageSize), "Page size must be between 1 and 300");
}

return _client
.GetAsync("phone/external_contacts")
.WithArgument("page_size", pageSize)
.WithArgument("next_page_token", nextPageToken)
.WithCancellationToken(cancellationToken)
.AsPaginatedResponseWithToken<ExternalContactDetails>("external_contacts");
}

/// <inheritdoc/>
public Task<ExternalContactDetails> GetDetailsAsync(string externalContactId, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(externalContactId))
{
throw new ArgumentNullException(nameof(externalContactId));
}

return _client
.GetAsync($"phone/external_contacts/{externalContactId}")
.WithCancellationToken(cancellationToken)
.AsObject<ExternalContactDetails>();
}

/// <inheritdoc/>
public Task<ExternalContact> AddAsync(ExternalContactDetails externalContact, CancellationToken cancellationToken = default)
{
return _client
.PostAsync("phone/external_contacts")
.WithJsonBody(externalContact)
.WithCancellationToken(cancellationToken)
.AsObject<ExternalContact>();
}

/// <inheritdoc/>
public Task DeleteAsync(string externalContactId, CancellationToken cancellationToken = default)
{
if (string.IsNullOrEmpty(externalContactId))
{
throw new ArgumentNullException(nameof(externalContactId));
}

return _client
.DeleteAsync($"phone/external_contacts/{externalContactId}")
.WithCancellationToken(cancellationToken)
.AsMessage();
}

/// <inheritdoc/>
public Task UpdateAsync(
ExternalContactDetails externalContact, CancellationToken cancellationToken = default)
{
if (externalContact == null)
{
throw new ArgumentNullException(nameof(externalContact));
}
else if (string.IsNullOrEmpty(externalContact.ExternalContactId))
{
throw new ArgumentNullException($"{nameof(externalContact)}.{nameof(externalContact.ExternalContactId)}");
}

return _client
.PatchAsync($"phone/external_contacts/{externalContact.ExternalContactId}")
.WithJsonBody(externalContact)
.WithCancellationToken(cancellationToken)
.AsMessage();
}
}
}
69 changes: 69 additions & 0 deletions Source/ZoomNet/Resources/IExternalContacts.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using System.Threading;
using System.Threading.Tasks;
using ZoomNet.Models;

namespace ZoomNet.Resources
{
/// <summary>
/// Allows you to access Zoom Phone API endpoints responsible for setting and retrieving data of external contacts.
/// </summary>
/// <remarks>
/// See <a href="https://developers.zoom.us/docs/api/rest/reference/phone/methods/#tag/External-Contacts">
/// Zoom API documentation</a> for more information.
/// </remarks>
public interface IExternalContacts
{
/// <summary>
/// Retrieves a list of all of an account's external contacts.
/// </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.
/// </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 external contacts in type of <see cref="ExternalContact"/>.
/// </returns>
Task<PaginatedResponseWithToken<ExternalContactDetails>> GetAllAsync(
int pageSize = 30,
string nextPageToken = null,
CancellationToken cancellationToken = default);

/// <summary>
/// Gets an external contact's information.
/// </summary>
/// <param name="externalContactId">The external contact id.</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 external contact details.</returns>
Task<ExternalContactDetails> GetDetailsAsync(
string externalContactId, CancellationToken cancellationToken = default);

/// <summary>
/// Adds an external contact.
/// </summary>
/// <param name="externalContact">The external contact information.</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 external contact details.</returns>
Task<ExternalContact> AddAsync(
ExternalContactDetails externalContact, CancellationToken cancellationToken = default);

/// <summary>
/// Removes an external contact.
/// </summary>
/// <param name="externalContactId">The external contact id.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task DeleteAsync(
string externalContactId, CancellationToken cancellationToken = default);

/// <summary>
/// Update an external contact information by <see cref="ExternalContact.ExternalContactId"/>.
/// </summary>
/// <param name="externalContact">External contact information.</param>
/// <param name="cancellationToken">A cancellation token that can be used to cancel the asynchronous operation.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task UpdateAsync(
ExternalContactDetails externalContact, CancellationToken cancellationToken = default);
}
}
Loading

0 comments on commit c4c4241

Please sign in to comment.