From d82fd3498cc4b41989a6e09c014d99947ceef5ca Mon Sep 17 00:00:00 2001 From: Volodymyr Dombrovskyi Date: Mon, 19 Dec 2022 21:41:40 +0100 Subject: [PATCH 01/22] (#225) Add support for the Get Meetings Report --- .../ZoomNet.IntegrationTests/Tests/Reports.cs | 24 ++-------- Source/ZoomNet/Models/ReportMeetingType.cs | 27 +++++++++++ Source/ZoomNet/Resources/IReports.cs | 21 ++++++++- Source/ZoomNet/Resources/Reports.cs | 45 +++++++++++++++++++ 4 files changed, 96 insertions(+), 21 deletions(-) create mode 100644 Source/ZoomNet/Models/ReportMeetingType.cs diff --git a/Source/ZoomNet.IntegrationTests/Tests/Reports.cs b/Source/ZoomNet.IntegrationTests/Tests/Reports.cs index b66e6784..0c407a27 100644 --- a/Source/ZoomNet.IntegrationTests/Tests/Reports.cs +++ b/Source/ZoomNet.IntegrationTests/Tests/Reports.cs @@ -16,34 +16,18 @@ public async Task RunAsync(User myUser, string[] myPermissions, IZoomClient clie await log.WriteLineAsync("\n***** REPORTS *****\n").ConfigureAwait(false); //GET ALL MEETINGS - var totalMeetings = await client - .Meetings.GetAllAsync(myUser.Id, MeetingListType.Scheduled, 30, null, cancellationToken) - .ConfigureAwait(false); - - var pastInstances = new List(); - - foreach (var meeting in totalMeetings.Records) - { - var pastMeetingInstances = await client.PastMeetings.GetInstancesAsync(meeting.Id, cancellationToken); - - foreach (var instance in pastMeetingInstances) - { - if (instance.StartedOn < DateTime.UtcNow.AddDays(-1) && !instance.Uuid.StartsWith("/")) - { - pastInstances.Add(instance); - } - } - } + var now = DateTime.UtcNow; + var pastMeetings = await client.Reports.GetMeetingsAsync(myUser.Id, now.Subtract(TimeSpan.FromDays(30)), now, ReportMeetingType.Past, 30, null, cancellationToken); int totalParticipants = 0; - foreach (var meeting in pastInstances) + foreach (var meeting in pastMeetings.Records) { var paginatedParticipants = await client.Reports.GetMeetingParticipantsAsync(meeting.Uuid, 30, null, cancellationToken); totalParticipants += paginatedParticipants.TotalRecords; } - await log.WriteLineAsync($"There are {pastInstances.Count} past instances of meetings with a total of {totalParticipants} participants for this user.").ConfigureAwait(false); + await log.WriteLineAsync($"There are {pastMeetings.Records.Length} past instances of meetings with a total of {totalParticipants} participants for this user.").ConfigureAwait(false); } } } diff --git a/Source/ZoomNet/Models/ReportMeetingType.cs b/Source/ZoomNet/Models/ReportMeetingType.cs new file mode 100644 index 00000000..562dfc94 --- /dev/null +++ b/Source/ZoomNet/Models/ReportMeetingType.cs @@ -0,0 +1,27 @@ +using System.Runtime.Serialization; + +namespace ZoomNet.Models; + +/// +/// Enumeration to indicate the type of meeting metrics are being returned for. +/// +public enum ReportMeetingType +{ + /// + /// All past meetings. + /// + [EnumMember(Value = "past")] + Past, + + /// + /// A single past user meeting. + /// + [EnumMember(Value = "pastOne")] + PastOne, + + /// + /// All past meetings the account's users hosted or joined. + /// + [EnumMember(Value = "pastJoined")] + PastJoined +} diff --git a/Source/ZoomNet/Resources/IReports.cs b/Source/ZoomNet/Resources/IReports.cs index 32a46268..9ee0a431 100644 --- a/Source/ZoomNet/Resources/IReports.cs +++ b/Source/ZoomNet/Resources/IReports.cs @@ -14,7 +14,7 @@ namespace ZoomNet.Resources public interface IReports { /// - /// Get a list of participants from past meetings with two or more participants. To see a list of participants for meetings with one participant use Dashboards.GetMeetingParticipantsAsync. + /// Get a list of participants from past meetings with two or more participants. To see a list of participants for meetings with one participant use . /// /// The meeting ID or meeting UUID. If given the meeting ID it will take the last meeting instance. /// The number of records returned within a single API call. @@ -28,5 +28,24 @@ public interface IReports /// An array of participants. /// Task> GetMeetingParticipantsAsync(string meetingId, int pageSize = 30, string pageToken = null, CancellationToken cancellationToken = default); + + /// + /// Get a list past meetings and webinars for a specified time period. The time range for the report is limited to a month and the month must fall within the past six months. + /// + /// The user ID or email address of the user. + /// Start date. + /// End date. + /// The meeting type to query for. + /// The number of records returned within a single API call. + /// + /// The next page token is used to paginate through large result sets. + /// A next page token will be returned whenever the set of available results exceeds the current page size. + /// The expiration period for this token is 15 minutes. + /// + /// The cancellation token. + /// + /// An array of meetings.. + /// + Task> GetMeetingsAsync(string userId, DateTime from, DateTime to, ReportMeetingType type = ReportMeetingType.Past, int pageSize = 30, string pageToken = null, CancellationToken cancellationToken = default); } } diff --git a/Source/ZoomNet/Resources/Reports.cs b/Source/ZoomNet/Resources/Reports.cs index 1700177a..cb3728ea 100644 --- a/Source/ZoomNet/Resources/Reports.cs +++ b/Source/ZoomNet/Resources/Reports.cs @@ -54,5 +54,50 @@ public Task> GetMeetingPart .WithCancellationToken(cancellationToken) .AsPaginatedResponseWithToken("participants"); } + + /// + /// Get a list past meetings and webinars for a specified time period. The time range for the report is limited to a month and the month must fall within the past six months. + /// + /// The user ID or email address of the user. + /// Start date. + /// End date. + /// The meeting type to query for. + /// The number of records returned within a single API call. + /// + /// The next page token is used to paginate through large result sets. + /// A next page token will be returned whenever the set of available results exceeds the current page size. + /// The expiration period for this token is 15 minutes. + /// + /// The cancellation token. + /// + /// An array of meetings.. + /// + public Task> GetMeetingsAsync(string userId, DateTime from, DateTime to, ReportMeetingType type, int pageSize = 30, string pageToken = null, CancellationToken cancellationToken = default) + { + if (to < from) + { + throw new ArgumentOutOfRangeException(nameof(to), $"Should be greater then or equal to {nameof(to)}."); + } + + if (to - from > TimeSpan.FromDays(30)) + { + throw new ArgumentOutOfRangeException(nameof(to), "The date range should not exceed one month."); + } + + if (pageSize < 1 || pageSize > 300) + { + throw new ArgumentOutOfRangeException(nameof(pageSize), "Page size must be between 1 and 300"); + } + + return _client + .GetAsync($"report/users/{userId}/meetings") + .WithArgument("from", from.ToZoomFormat(dateOnly: true)) + .WithArgument("to", to.ToZoomFormat(dateOnly: true)) + .WithArgument("type", type.ToEnumString()) + .WithArgument("page_size", pageSize) + .WithArgument("next_page_token", pageToken) + .WithCancellationToken(cancellationToken) + .AsPaginatedResponseWithToken("meetings"); + } } } From 60bc2b1f5a1be95a08f65031b9bfe9d6fe8ed674 Mon Sep 17 00:00:00 2001 From: jericho Date: Wed, 21 Dec 2022 20:58:01 -0500 Subject: [PATCH 02/22] Fix typo --- Source/ZoomNet/Resources/Reports.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ZoomNet/Resources/Reports.cs b/Source/ZoomNet/Resources/Reports.cs index cb3728ea..f1df1cc0 100644 --- a/Source/ZoomNet/Resources/Reports.cs +++ b/Source/ZoomNet/Resources/Reports.cs @@ -76,7 +76,7 @@ public Task> GetMeetingsAsync(string use { if (to < from) { - throw new ArgumentOutOfRangeException(nameof(to), $"Should be greater then or equal to {nameof(to)}."); + throw new ArgumentOutOfRangeException(nameof(to), $"Should be greater then or equal to {nameof(from)}."); } if (to - from > TimeSpan.FromDays(30)) From 1bea1e6ab67f17bddb95da6618329fb5460045c3 Mon Sep 17 00:00:00 2001 From: jericho Date: Wed, 21 Dec 2022 20:58:55 -0500 Subject: [PATCH 03/22] Fix issue in Meetings integration test --- Source/ZoomNet.IntegrationTests/Tests/Meetings.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/ZoomNet.IntegrationTests/Tests/Meetings.cs b/Source/ZoomNet.IntegrationTests/Tests/Meetings.cs index da5fa15d..19a8e04e 100644 --- a/Source/ZoomNet.IntegrationTests/Tests/Meetings.cs +++ b/Source/ZoomNet.IntegrationTests/Tests/Meetings.cs @@ -39,7 +39,10 @@ public async Task RunAsync(User myUser, string[] myPermissions, IZoomClient clie }); await Task.WhenAll(cleanUpTasks).ConfigureAwait(false); - var templates = await client.Meetings.GetTemplatesAsync(myUser.Id, cancellationToken).ConfigureAwait(false); + // For an unknown reason, using myUser.Id to retrieve meeting templates causes an "Invalid token" exception. + // That's why I use "me" on the following line: + var templates = await client.Meetings.GetTemplatesAsync("me", cancellationToken).ConfigureAwait(false); + await log.WriteLineAsync($"Retrieved {templates.Length} meeting templates").ConfigureAwait(false); var settings = new MeetingSettings() { From 7322240c1105d96a59d1aac3f694aa9cf655fed0 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:27:31 -0500 Subject: [PATCH 04/22] Improve Readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3d906479..78000d8c 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ ## About +The ZoomNet library simplifies connecting with the Zoom.us API and interacting with the various endpoints. Additionaly, the library includes a parser that allows you to process inbound webhook messages sent to you by the Zoom API. + ## Installation From b8b0305680de69cdf2775fb363b567f86ca37017 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:28:18 -0500 Subject: [PATCH 05/22] Add the recently added ReportMeetingType type to serialization context --- Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs index 36a48901..22885c2f 100644 --- a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs +++ b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs @@ -137,6 +137,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.RegistrationQuestionsForWebinar))] [JsonSerializable(typeof(ZoomNet.Models.RegistrationType))] [JsonSerializable(typeof(ZoomNet.Models.ReportMeetingParticipant))] + [JsonSerializable(typeof(ZoomNet.Models.ReportMeetingType))] [JsonSerializable(typeof(ZoomNet.Models.ReportParticipant))] [JsonSerializable(typeof(ZoomNet.Models.Role))] [JsonSerializable(typeof(ZoomNet.Models.RoleInPurchaseProcess))] @@ -360,6 +361,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.RegistrationQuestionsForWebinar[]))] [JsonSerializable(typeof(ZoomNet.Models.RegistrationType[]))] [JsonSerializable(typeof(ZoomNet.Models.ReportMeetingParticipant[]))] + [JsonSerializable(typeof(ZoomNet.Models.ReportMeetingType[]))] [JsonSerializable(typeof(ZoomNet.Models.ReportParticipant[]))] [JsonSerializable(typeof(ZoomNet.Models.Role[]))] [JsonSerializable(typeof(ZoomNet.Models.RoleInPurchaseProcess[]))] @@ -503,6 +505,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.RegistrationCustomQuestionTypeForWebinar?))] [JsonSerializable(typeof(ZoomNet.Models.RegistrationField?))] [JsonSerializable(typeof(ZoomNet.Models.RegistrationType?))] + [JsonSerializable(typeof(ZoomNet.Models.ReportMeetingType?))] [JsonSerializable(typeof(ZoomNet.Models.RoleInPurchaseProcess?))] [JsonSerializable(typeof(ZoomNet.Models.ScreenshareContentType?))] [JsonSerializable(typeof(ZoomNet.Models.StreamingService?))] From c33f8ff72b6f754aa20c852a3b90b5c80b5126a2 Mon Sep 17 00:00:00 2001 From: Jericho Date: Fri, 23 Sep 2022 12:11:57 -0400 Subject: [PATCH 06/22] Parse "endpoint.url_validation" webhook event --- Source/ZoomNet/Json/WebhookEventConverter.cs | 5 +++++ .../Webhooks/EndpointUrlValidationEvent.cs | 19 +++++++++++++++++++ Source/ZoomNet/Models/Webhooks/EventType.cs | 6 ++++++ 3 files changed, 30 insertions(+) create mode 100644 Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs diff --git a/Source/ZoomNet/Json/WebhookEventConverter.cs b/Source/ZoomNet/Json/WebhookEventConverter.cs index 560438d6..dcd27030 100644 --- a/Source/ZoomNet/Json/WebhookEventConverter.cs +++ b/Source/ZoomNet/Json/WebhookEventConverter.cs @@ -269,6 +269,11 @@ public override Event Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe webinarParticipantLeftEvent.Participant = payloadJsonProperty.GetProperty("object/participant", true).Value.ToObject(); webHookEvent = webinarParticipantLeftEvent; break; + case EventType.EndpointUrlValidation: + var endpointUrlValidationEvent = payloadJsonProperty.ToObject(options); + endpointUrlValidationEvent.PlainToken = payloadJsonProperty.GetPropertyValue("payload/plainToken"); + webHookEvent = endpointUrlValidationEvent; + break; default: throw new Exception($"{eventType} is an unknown event type"); } diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs new file mode 100644 index 00000000..f719285e --- /dev/null +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -0,0 +1,19 @@ +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using ZoomNet.Json; + +namespace ZoomNet.Models.Webhooks +{ + /// + /// This event is triggered when Zoom wants to validate the event notification endpoint URL you have configured in your account. + /// + public class EndpointUrlValidationEvent : Event + { + /// + /// Gets or sets the token. + /// + public string PlainToken { get; set; } + } +} diff --git a/Source/ZoomNet/Models/Webhooks/EventType.cs b/Source/ZoomNet/Models/Webhooks/EventType.cs index 70bba9b6..291e1ac7 100644 --- a/Source/ZoomNet/Models/Webhooks/EventType.cs +++ b/Source/ZoomNet/Models/Webhooks/EventType.cs @@ -257,5 +257,11 @@ public enum EventType /// [EnumMember(Value = "webinar.updated")] WebinarUpdated, + + /// + /// Zoom is requesting that you validate the endpoint. + /// + [EnumMember(Value = "endpoint.url_validation")] + EndpointUrlValidation, } } From 1838f3b39c3a1281c2dbfba5f8bdc80f9ada275b Mon Sep 17 00:00:00 2001 From: Jericho Date: Fri, 23 Sep 2022 12:12:54 -0400 Subject: [PATCH 07/22] Add method to conveniently generate the response to a request from Zoom to validate your webhook URL --- .../Webhooks/EndpointUrlValidationEvent.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs index f719285e..9136a74e 100644 --- a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -15,5 +15,26 @@ public class EndpointUrlValidationEvent : Event /// Gets or sets the token. /// public string PlainToken { get; set; } + + /// + /// Generates the payload that should be returned to Zoom when your are asked to validate your webhook endpoint URL. + /// + /// Your webhoop app's secret token. + /// The payload to be returned to Zoom. + public string GenerateUrlValidationResponse(string secretToken) + { + // Generate the encrypted token according to Zoom's instructions: https://marketplace.zoom.us/docs/api-reference/webhook-reference/#verify-webhook-events + var crypto = new HMACSHA256(Encoding.UTF8.GetBytes(secretToken)); + var encryptedToken = crypto.ComputeHash(Encoding.UTF8.GetBytes(this.PlainToken)).ToHexString(); + + var data = new JsonObject + { + { "plainToken", this.PlainToken }, + { "encryptedToken", encryptedToken }, + }; + + var jsonString = JsonSerializer.Serialize(data, typeof(JsonObject), ZoomNetJsonFormatter.SerializationContext); + return jsonString; + } } } From 052c4ea38ff326dc41b28918469310ddc9929d3c Mon Sep 17 00:00:00 2001 From: Jericho Date: Sat, 24 Sep 2022 15:19:04 -0400 Subject: [PATCH 08/22] Fix codes samples in README.md; provide code sample for webhook endpoint validation; provide an "ultimate" code sample which combines all the webhook parsing features --- README.md | 127 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 78000d8c..c5169290 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,6 @@ var zoomClient = new ZoomClient(connectionInfo); Here's a basic example of a .net 6.0 API controller which parses the webhook from Zoom: ```csharp using Microsoft.AspNetCore.Mvc; -using StrongGrid; namespace WebApplication1.Controllers { @@ -169,10 +168,9 @@ namespace WebApplication1.Controllers public class ZoomWebhooksController : ControllerBase { [HttpPost] - [Route("Event")] public async Task ReceiveEvent() { - var parser = new WebhookParser(); + var parser = new ZoomNet.WebhookParser(); var event = await parser.ParseEventWebhookAsync(Request.Body).ConfigureAwait(false); // ... do something with the event ... @@ -199,8 +197,6 @@ The `WebhookParser` class has a method called `VerifyAndParseEventWebhookAsync`w ```csharp using Microsoft.AspNetCore.Mvc; -using StrongGrid; -using System.Security; namespace WebApplication1.Controllers { @@ -211,28 +207,117 @@ namespace WebApplication1.Controllers [HttpPost] public async Task ReceiveEvent() { - try - { - // Get your secret token - var secretToken = "... your app's secret token ..."; + // Your webhook app's secret token + var secretToken = "... your app's secret token ..."; + + // Get the signature and the timestamp from the request headers + // SIGNATURE_HEADER_NAME and TIMESTAMP_HEADER_NAME are two convenient constants provided by ZoomNet so you don't have to remember the actual names of the headers + var signature = Request.Headers[ZoomNet.WebhookParser.SIGNATURE_HEADER_NAME].SingleOrDefault(); + var timestamp = Request.Headers[ZoomNet.WebhookParser.TIMESTAMP_HEADER_NAME].SingleOrDefault(); + + var parser = new ZoomNet.WebhookParser(); + + // The signature will be automatically validated and a security exception thrown if unable to validate + var zoomEvent = await parser.VerifyAndParseEventWebhookAsync(Request.Body, secretToken, signature, timestamp).ConfigureAwait(false); + + // ... do something with the event... + + return Ok(); + } + } +} +``` + +### Responding to requests from Zoom to validate your webhook endpoint + +When you initially configure the URL where you want Zoom to post the webhooks, Zoom will send a request to this URL and you are expected to respond to this validation challenge in a way that can be validated by the Zoom API. Zoom calls this a "Challenge-Response check (CRC)". Assuming this initial validation is successful, the Zoom API will repeat this validation process every 72 hours. You can of course manually craft this reponse by following Zoom's [instructions](https://marketplace.zoom.us/docs/api-reference/webhook-reference/#validate-your-webhook-endpoint). +However, if you want to avoid learning the intricacies of the reponse expected by Zoon and you simply want this response to be conveniently generated for you, ZoomNet can help! +The `EndpointUrlValidationEvent` class has a method called `GenerateUrlValidationResponse` which will generate the string that you must include in your HTTP200 response. +Here's how it works: + +```csharp +using Microsoft.AspNetCore.Mvc; + +namespace WebApplication1.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ZoomWebhooksController : ControllerBase + { + [HttpPost] + public async Task ReceiveEvent() + { + // Your webhook app's secret token + var secretToken = "... your app's secret token ..."; + + var parser = new ZoomNet.WebhookParser(); + var event = await parser.ParseEventWebhookAsync(Request.Body).ConfigureAwait(false); + + var endpointUrlValidationEvent = zoomEvent as EndpointUrlValidationEvent; + var responsePayload = endpointUrlValidationEvent.GenerateUrlValidationResponse(secretToken); + return Ok(responsePayload); + } + } +} +``` - // Get the signature and the timestamp from the request headers - var signature = Request.Headers[WebhookParser.SIGNATURE_HEADER_NAME].SingleOrDefault(); // SIGNATURE_HEADER_NAME is a convenient constant provided by ZoomNet so you don't have to remember the name of the header - var timestamp = Request.Headers[WebhookParser.TIMESTAMP_HEADER_NAME].SingleOrDefault(); // TIMESTAMP_HEADER_NAME is a convenient constant provided by ZoomNet so you don't have to remember the name of the header +### The ultimate webhook controller - // Parse the event. The signature will be automatically validated and a security exception thrown if unable to validate - var parser = new WebhookParser(); - var event = await parser.VerifyAndParseEventWebhook(Request.Body, secretToken, signature, timestamp).ConfigureAwait(false); +Here's the "ultimate" webhook controller which combines all the above features: - // ... do something with the event... +```csharp +using Microsoft.AspNetCore.Mvc; + +namespace WebApplication1.Controllers +{ + [Route("api/[controller]")] + [ApiController] + public class ZoomWebhooksController : ControllerBase + { + [HttpPost] + public async Task ReceiveEvent() + { + // Your webhook app's secret token + var secretToken = "... your app's secret token ..."; + + // SIGNATURE_HEADER_NAME and TIMESTAMP_HEADER_NAME are two convenient constants provided by ZoomNet so you don't have to remember the actual name of the headers + var signature = Request.Headers[ZoomNet.WebhookParser.SIGNATURE_HEADER_NAME].SingleOrDefault(); + var timestamp = Request.Headers[ZoomNet.WebhookParser.TIMESTAMP_HEADER_NAME].SingleOrDefault(); + + var parser = new ZoomNet.WebhookParser(); + Event zoomEvent; + + if (!string.IsNullOrEmpty(signature) && !string.IsNullOrEmpty(timestamp)) + { + try + { + zoomEvent = await parser.VerifyAndParseEventWebhookAsync(Request.Body, secretToken, signature, timestamp).ConfigureAwait(false); + } + catch (SecurityException e) + { + // Unable to validate the data. Therefore you should consider the request as suspicious + throw; + } } - catch (SecurityException e) + else { - // ... unable to validate the data ... + zoomEvent = await parser.ParseEventWebhookAsync(Request.Body).ConfigureAwait(false); } - return Ok(); + if (zoomEvent.EventType == EventType.EndpointUrlValidation) + { + // It's important to include the payload along with your HTTP200 response. This is how you let Zoom know that your URL is valid + var endpointUrlValidationEvent = zoomEvent as EndpointUrlValidationEvent; + var responsePayload = endpointUrlValidationEvent.GenerateUrlValidationResponse(secretToken); + return Ok(responsePayload); + } + else + { + // ... do something with the event ... + + return Ok(); + } } - } + } } -``` \ No newline at end of file +``` From e6faeda2efbd31102b22eb1f8c4c65b3df0e92ee Mon Sep 17 00:00:00 2001 From: Jericho Date: Tue, 4 Oct 2022 12:50:44 -0400 Subject: [PATCH 09/22] Fix typos in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c5169290..85b96cb5 100644 --- a/README.md +++ b/README.md @@ -231,7 +231,7 @@ namespace WebApplication1.Controllers ### Responding to requests from Zoom to validate your webhook endpoint When you initially configure the URL where you want Zoom to post the webhooks, Zoom will send a request to this URL and you are expected to respond to this validation challenge in a way that can be validated by the Zoom API. Zoom calls this a "Challenge-Response check (CRC)". Assuming this initial validation is successful, the Zoom API will repeat this validation process every 72 hours. You can of course manually craft this reponse by following Zoom's [instructions](https://marketplace.zoom.us/docs/api-reference/webhook-reference/#validate-your-webhook-endpoint). -However, if you want to avoid learning the intricacies of the reponse expected by Zoon and you simply want this response to be conveniently generated for you, ZoomNet can help! +However, if you want to avoid learning the intricacies of the reponse expected by Zoom and you simply want this response to be conveniently generated for you, ZoomNet can help! The `EndpointUrlValidationEvent` class has a method called `GenerateUrlValidationResponse` which will generate the string that you must include in your HTTP200 response. Here's how it works: From 9a7d6d41cca6c7c848de27a92b6fbf6b37b39bd5 Mon Sep 17 00:00:00 2001 From: Jericho Date: Tue, 1 Nov 2022 13:40:32 -0400 Subject: [PATCH 10/22] Fix due to recent rebase --- Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs index 9136a74e..414adfb8 100644 --- a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -33,7 +33,7 @@ public string GenerateUrlValidationResponse(string secretToken) { "encryptedToken", encryptedToken }, }; - var jsonString = JsonSerializer.Serialize(data, typeof(JsonObject), ZoomNetJsonFormatter.SerializationContext); + var jsonString = JsonSerializer.Serialize(data, typeof(JsonObject), JsonFormatter.SerializationContext); return jsonString; } } From dfeab2d9def1802780920d3b8bf1065270a7c34d Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:21:13 -0500 Subject: [PATCH 11/22] Fix EndpointUrlValidation deserialization --- Source/ZoomNet/Json/WebhookEventConverter.cs | 1 - Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs | 2 ++ Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/ZoomNet/Json/WebhookEventConverter.cs b/Source/ZoomNet/Json/WebhookEventConverter.cs index dcd27030..2efea824 100644 --- a/Source/ZoomNet/Json/WebhookEventConverter.cs +++ b/Source/ZoomNet/Json/WebhookEventConverter.cs @@ -271,7 +271,6 @@ public override Event Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSe break; case EventType.EndpointUrlValidation: var endpointUrlValidationEvent = payloadJsonProperty.ToObject(options); - endpointUrlValidationEvent.PlainToken = payloadJsonProperty.GetPropertyValue("payload/plainToken"); webHookEvent = endpointUrlValidationEvent; break; default: diff --git a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs index 22885c2f..ef60d8b8 100644 --- a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs +++ b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs @@ -172,6 +172,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.WaitingRoomSettings))] [JsonSerializable(typeof(ZoomNet.Models.WebhookParticipant))] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.AppDeauthorizedEvent), TypeInfoPropertyName = "WebhooksAppDeauthorizedEvent")] + [JsonSerializable(typeof(ZoomNet.Models.Webhooks.EndpointUrlValidationEvent), TypeInfoPropertyName = "WebhooksEndpointUrlValidationEvent")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.Event), TypeInfoPropertyName = "WebhooksEvent")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.EventType), TypeInfoPropertyName = "WebhooksEventType")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.MeetingCreatedEvent), TypeInfoPropertyName = "WebhooksMeetingCreatedEvent")] @@ -396,6 +397,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.WaitingRoomSettings[]))] [JsonSerializable(typeof(ZoomNet.Models.WebhookParticipant[]))] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.AppDeauthorizedEvent[]), TypeInfoPropertyName = "WebhooksAppDeauthorizedEventArray")] + [JsonSerializable(typeof(ZoomNet.Models.Webhooks.EndpointUrlValidationEvent[]), TypeInfoPropertyName = "WebhooksEndpointUrlValidationEventArray")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.Event[]), TypeInfoPropertyName = "WebhooksEventArray")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.EventType[]), TypeInfoPropertyName = "WebhooksEventTypeArray")] [JsonSerializable(typeof(ZoomNet.Models.Webhooks.MeetingCreatedEvent[]), TypeInfoPropertyName = "WebhooksMeetingCreatedEventArray")] diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs index 414adfb8..a5f9acf6 100644 --- a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -2,6 +2,7 @@ using System.Text; using System.Text.Json; using System.Text.Json.Nodes; +using System.Text.Json.Serialization; using ZoomNet.Json; namespace ZoomNet.Models.Webhooks @@ -14,6 +15,7 @@ public class EndpointUrlValidationEvent : Event /// /// Gets or sets the token. /// + [JsonPropertyName("plainToken")] public string PlainToken { get; set; } /// From 050f911e176eec26c089b0168d1925064f7a54ab Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:25:42 -0500 Subject: [PATCH 12/22] Change encoding to ASCII when generating the Webhook Url validation response I'm not sure whether to use UTF8 or ASCII encoding but testing indicates that ASCII works so let's go with that --- Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs index a5f9acf6..4f252954 100644 --- a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -26,8 +26,8 @@ public class EndpointUrlValidationEvent : Event public string GenerateUrlValidationResponse(string secretToken) { // Generate the encrypted token according to Zoom's instructions: https://marketplace.zoom.us/docs/api-reference/webhook-reference/#verify-webhook-events - var crypto = new HMACSHA256(Encoding.UTF8.GetBytes(secretToken)); - var encryptedToken = crypto.ComputeHash(Encoding.UTF8.GetBytes(this.PlainToken)).ToHexString(); + var crypto = new HMACSHA256(Encoding.ASCII.GetBytes(secretToken)); + var encryptedToken = crypto.ComputeHash(Encoding.ASCII.GetBytes(this.PlainToken)).ToHexString(); var data = new JsonObject { From 099ab200dfa804ef457d44e1a934b7f7d3c6512c Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:39:58 -0500 Subject: [PATCH 13/22] Upgrade the StyleCop analyzer nuget package to the latest beta version because it contains a fix for an annoying SA1000 warning The code that triggers the warning DateTime myDate = new(); // notice the absence of space between 'new' and the parenthesis --- Source/ZoomNet/Extensions/Internal.cs | 2 +- Source/ZoomNet/ZoomNet.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index 0dd8072d..d91048b5 100644 --- a/Source/ZoomNet/Extensions/Internal.cs +++ b/Source/ZoomNet/Extensions/Internal.cs @@ -35,7 +35,7 @@ internal enum UnixTimePrecision Milliseconds = 1 } - private static readonly DateTime EPOCH = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + private static readonly DateTime EPOCH = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); /// /// Converts a 'unix time', which is expressed as the number of seconds (or milliseconds) since diff --git a/Source/ZoomNet/ZoomNet.csproj b/Source/ZoomNet/ZoomNet.csproj index e0ce5d5c..93fa63d1 100644 --- a/Source/ZoomNet/ZoomNet.csproj +++ b/Source/ZoomNet/ZoomNet.csproj @@ -41,7 +41,7 @@ - + From d2414519a0cbe9a40d7f66d9ac3d8e5f3b4ff504 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 10:40:37 -0500 Subject: [PATCH 14/22] Upgrade nuget package --- Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj b/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj index 239efa7a..56c4171a 100644 --- a/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj +++ b/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj @@ -12,7 +12,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + From 143d7726315a697893de2b085084fed5dd384dd9 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 11:00:41 -0500 Subject: [PATCH 15/22] Fix warnings reported by StyleCop Use compound assignment Documentation text should end with a period --- Source/ZoomNet/Extensions/Internal.cs | 2 +- Source/ZoomNet/Models/ChatChannelRole.cs | 4 +- Source/ZoomNet/Models/Country.cs | 475 +++++++++--------- Source/ZoomNet/Models/DashboardMeetingType.cs | 4 +- Source/ZoomNet/Models/DataCenterRegion.cs | 28 +- .../ZoomNet/Models/InterpretationLanguage.cs | 18 +- Source/ZoomNet/Models/Language.cs | 76 +-- Source/ZoomNet/Models/MeetingType.cs | 2 +- Source/ZoomNet/Models/NumberOfEmployees.cs | 18 +- Source/ZoomNet/Models/PresenceStatus.cs | 2 +- Source/ZoomNet/Models/PurchasingTimeFrame.cs | 12 +- Source/ZoomNet/Models/RecordingFileType.cs | 2 +- .../ZoomNet/Models/RoleInPurchaseProcess.cs | 10 +- Source/ZoomNet/Models/StreamingService.cs | 8 +- .../ZoomNet/Models/VirtualBackgroundType.cs | 4 +- 15 files changed, 333 insertions(+), 332 deletions(-) diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index d91048b5..3885323c 100644 --- a/Source/ZoomNet/Extensions/Internal.cs +++ b/Source/ZoomNet/Extensions/Internal.cs @@ -163,7 +163,7 @@ internal static async Task ReadAsStringAsync(this HttpContent httpConten { var contentStream = await httpContent.ReadAsStreamAsync().ConfigureAwait(false); - if (encoding == null) encoding = httpContent.GetEncoding(Encoding.UTF8); + encoding ??= httpContent.GetEncoding(Encoding.UTF8); // This is important: we must make a copy of the response stream otherwise we would get an // exception on subsequent attempts to read the content of the stream diff --git a/Source/ZoomNet/Models/ChatChannelRole.cs b/Source/ZoomNet/Models/ChatChannelRole.cs index dd042502..9e298992 100644 --- a/Source/ZoomNet/Models/ChatChannelRole.cs +++ b/Source/ZoomNet/Models/ChatChannelRole.cs @@ -14,13 +14,13 @@ public enum ChatChannelRole Owner, /// - /// Past + /// Past. /// [EnumMember(Value = "admin")] Administrator, /// - /// PastOne + /// PastOne. /// [EnumMember(Value = "member")] Member diff --git a/Source/ZoomNet/Models/Country.cs b/Source/ZoomNet/Models/Country.cs index 5f2648c7..36868474 100644 --- a/Source/ZoomNet/Models/Country.cs +++ b/Source/ZoomNet/Models/Country.cs @@ -7,947 +7,948 @@ namespace ZoomNet.Models /// public enum Country { - /// United Arab Emirates + /// United Arab Emirates. [EnumMember(Value = "AE")] United_Arab_Emirates, - /// Andorra + /// Andorra. [EnumMember(Value = "AD")] Andorra, - /// Afghanistan + /// Afghanistan. [EnumMember(Value = "AF")] Afghanistan, - /// Antigua and Barbuda + /// Antigua and Barbuda. [EnumMember(Value = "AG")] Antigua_and_Barbuda, - /// Anguilla + /// Anguilla. [EnumMember(Value = "AI")] Anguilla, - /// Albania + /// Albania. [EnumMember(Value = "AL")] Albania, - /// Armenia + /// Armenia. [EnumMember(Value = "AM")] Armenia, - /// Netherlands Antilles + /// Netherlands Antilles. [EnumMember(Value = "AN")] Netherlands_Antilles, - /// Angola + /// Angola. [EnumMember(Value = "AO")] Angola, - /// Antarctica + /// Antarctica. [EnumMember(Value = "AQ")] Antarctica, - /// Argentina + /// Argentina. [EnumMember(Value = "AR")] Argentina, - /// American Samoa + /// American Samoa. [EnumMember(Value = "AS")] American_Samoa, - /// Austria + /// Austria. [EnumMember(Value = "AT")] Austria, - /// Australia + /// Australia. [EnumMember(Value = "AU")] Australia, - /// Aruba + /// Aruba. [EnumMember(Value = "AW")] Aruba, - /// Aland Islands + /// Aland Islands. [EnumMember(Value = "AX")] Aland_Islands, - /// Azerbaijan + /// Azerbaijan. [EnumMember(Value = "AZ")] Azerbaijan, - /// Bosnia and Herzegovina + /// Bosnia and Herzegovina. [EnumMember(Value = "BA")] Bosnia_and_Herzegovina, - /// Barbados + /// Barbados. [EnumMember(Value = "BB")] Barbados, - /// Bangladesh + /// Bangladesh. [EnumMember(Value = "BD")] Bangladesh, - /// Belgium + /// Belgium. [EnumMember(Value = "BE")] Belgium, - /// Burkina Faso + /// Burkina Faso. [EnumMember(Value = "BF")] Burkina_Faso, - /// Bulgaria + /// Bulgaria. [EnumMember(Value = "BG")] Bulgaria, - /// Bahrain + /// Bahrain. [EnumMember(Value = "BH")] Bahrain, - /// Burundi + /// Burundi. [EnumMember(Value = "BI")] Burundi, - /// Benin + /// Benin. [EnumMember(Value = "BJ")] Benin, - /// Bermuda + /// Bermuda. [EnumMember(Value = "BM")] Bermuda, - /// Brunei Darussalam + /// Brunei Darussalam. [EnumMember(Value = "BN")] Brunei_Darussalam, - /// Bolivia + /// Bolivia. [EnumMember(Value = "BO")] Bolivia, - /// Brazil + /// Brazil. [EnumMember(Value = "BR")] Brazil, - /// Bahamas + /// Bahamas. [EnumMember(Value = "BS")] Bahamas, - /// Bhutan + /// Bhutan. [EnumMember(Value = "BT")] Bhutan, - /// Bouvet Island + /// Bouvet Island. [EnumMember(Value = "BV")] Bouvet_Island, - /// Botswana + /// Botswana. [EnumMember(Value = "BW")] Botswana, - /// Belarus + /// Belarus. [EnumMember(Value = "BY")] Belarus, - /// Belize + /// Belize. [EnumMember(Value = "BZ")] Belize, - /// Canada + /// Canada. [EnumMember(Value = "CA")] Canada, - /// The Democratic Republic of The Congo + /// The Democratic Republic of The Congo. [EnumMember(Value = "CD")] The_Democratic_Republic_of_The_Congo, - /// Central African Republic + /// Central African Republic. [EnumMember(Value = "CF")] Central_African_Republic, - /// Congo + /// Congo. [EnumMember(Value = "CG")] Congo, - /// Switzerland + /// Switzerland. [EnumMember(Value = "CH")] Switzerland, - /// Cote D'Ivoire + /// Cote D'Ivoire. [EnumMember(Value = "CI")] Cote_D_Ivoire, - /// Cook Islands + /// Cook Islands. [EnumMember(Value = "CK")] Cook_Islands, - /// Chile + /// Chile. [EnumMember(Value = "CL")] Chile, - /// Cameroon + /// Cameroon. [EnumMember(Value = "CM")] Cameroon, - /// China + /// China. [EnumMember(Value = "CN")] China, - /// Colombia + /// Colombia. [EnumMember(Value = "CO")] Colombia, - /// Costa Rica + /// Costa Rica. [EnumMember(Value = "CR")] Costa_Rica, - /// Serbia and Montenegro + /// Serbia and Montenegro. [EnumMember(Value = "CS")] Serbia_and_Montenegro, - /// Cape Verde + /// Cape Verde. [EnumMember(Value = "CV")] Cape_Verde, - /// Cyprus + /// Cyprus. [EnumMember(Value = "CY")] Cyprus, - /// Czech Republic + /// Czech Republic. [EnumMember(Value = "CZ")] Czech_Republic, - /// Germany + /// Germany. [EnumMember(Value = "DE")] Germany, - /// Djibouti + /// Djibouti. [EnumMember(Value = "DJ")] Djibouti, - /// Denmark + /// Denmark. [EnumMember(Value = "DK")] Denmark, - /// Dominica + /// Dominica. [EnumMember(Value = "DM")] Dominica, - /// Dominican Republic + /// Dominican Republic. [EnumMember(Value = "DO")] Dominican_Republic, - /// Algeria + /// Algeria. [EnumMember(Value = "DZ")] Algeria, - /// Ecuador + /// Ecuador. [EnumMember(Value = "EC")] Ecuador, - /// Estonia + /// Estonia. [EnumMember(Value = "EE")] Estonia, - /// Egypt + /// Egypt. [EnumMember(Value = "EG")] Egypt, - /// Eritrea + /// Eritrea. [EnumMember(Value = "ER")] Eritrea, - /// Spain + /// Spain. [EnumMember(Value = "ES")] Spain, - /// Ethiopia + /// Ethiopia. [EnumMember(Value = "ET")] Ethiopia, - /// Finland + /// Finland. [EnumMember(Value = "FI")] Finland, - /// Fiji + /// Fiji. [EnumMember(Value = "FJ")] Fiji, - /// Falkland Islands (Malvinas) + /// Falkland Islands (Malvinas). [EnumMember(Value = "FK")] Falkland_Islands_Malvinas, - /// Federated States of Micronesia + /// Federated States of Micronesia. [EnumMember(Value = "FM")] Federated_States_of_Micronesia, - /// Faroe Islands + /// Faroe Islands. [EnumMember(Value = "FO")] Faroe_Islands, - /// France + /// France. [EnumMember(Value = "FR")] France, - /// Gabon + /// Gabon. [EnumMember(Value = "GA")] Gabon, - /// United Kingdom of Great Britain and Northern Ireland + /// United Kingdom of Great Britain and Northern Ireland. [EnumMember(Value = "GB")] United_Kingdom_of_Great_Britain_and_Northern_Ireland, - /// Grenada + /// Grenada. [EnumMember(Value = "GD")] Grenada, - /// Georgia + /// Georgia. [EnumMember(Value = "GE")] Georgia, - /// French Guiana + /// French Guiana. [EnumMember(Value = "GF")] French_Guiana, - /// Guernsey + /// Guernsey. [EnumMember(Value = "GG")] Guernsey, - /// Ghana + /// Ghana. [EnumMember(Value = "GH")] Ghana, - /// Gibraltar + /// Gibraltar. [EnumMember(Value = "GI")] Gibraltar, - /// Greenland + /// Greenland. [EnumMember(Value = "GL")] Greenland, - /// Gambia + /// Gambia. [EnumMember(Value = "GM")] Gambia, - /// Guinea + /// Guinea. [EnumMember(Value = "GN")] Guinea, - /// Guadeloupe + /// Guadeloupe. [EnumMember(Value = "GP")] Guadeloupe, - /// Equatorial Guinea + /// Equatorial Guinea. [EnumMember(Value = "GQ")] Equatorial_Guinea, - /// Greece + /// Greece. [EnumMember(Value = "GR")] Greece, - /// South Georgia and The South Sandwich Islands + /// South Georgia and The South Sandwich Islands. [EnumMember(Value = "GS")] South_Georgia_and_The_South_Sandwich_Islands, - /// Guatemala + /// Guatemala. [EnumMember(Value = "GT")] Guatemala, - /// Guam + /// Guam. [EnumMember(Value = "GU")] Guam, - /// Guinea-Bissau + /// Guinea-Bissau. [EnumMember(Value = "GW")] Guinea_Bissau, - /// Guyana + /// Guyana. [EnumMember(Value = "GY")] Guyana, - /// Hong Kong + /// Hong Kong. [EnumMember(Value = "HK")] Hong_Kong, - /// Honduras + /// Honduras. [EnumMember(Value = "HN")] Honduras, - /// Croatia + /// Croatia. [EnumMember(Value = "HR")] Croatia, - /// Haiti + /// Haiti. [EnumMember(Value = "HT")] Haiti, - /// Hungary + /// Hungary. [EnumMember(Value = "HU")] Hungary, - /// Indonesia + /// Indonesia. [EnumMember(Value = "ID")] Indonesia, - /// Ireland + /// Ireland. [EnumMember(Value = "IE")] Ireland, - /// Israel + /// Israel. [EnumMember(Value = "IL")] Israel, - /// Isle of Man + /// Isle of Man. [EnumMember(Value = "IM")] Isle_of_Man, - /// India + /// India. [EnumMember(Value = "IN")] India, - /// British Indian Ocean Territory + /// British Indian Ocean Territory. [EnumMember(Value = "IO")] British_Indian_Ocean_Territory, - /// Iraq + /// Iraq. [EnumMember(Value = "IQ")] Iraq, - /// Iceland + /// Iceland. [EnumMember(Value = "IS")] Iceland, - /// Italy + /// Italy. [EnumMember(Value = "IT")] Italy, - /// Jersey + /// Jersey. [EnumMember(Value = "JE")] Jersey, - /// Jamaica + /// Jamaica. [EnumMember(Value = "JM")] Jamaica, - /// Jordan + /// Jordan. [EnumMember(Value = "JO")] Jordan, - /// Japan + /// Japan. [EnumMember(Value = "JP")] Japan, - /// Kenya + /// Kenya. [EnumMember(Value = "KE")] Kenya, - /// Kyrgyzstan + /// Kyrgyzstan. [EnumMember(Value = "KG")] Kyrgyzstan, - /// Cambodia + /// Cambodia. [EnumMember(Value = "KH")] Cambodia, - /// Kiribati + /// Kiribati. [EnumMember(Value = "KI")] Kiribati, - /// Comoros + /// Comoros. [EnumMember(Value = "KM")] Comoros, - /// Saint Kitts and Nevis + /// Saint Kitts and Nevis. [EnumMember(Value = "KN")] Saint_Kitts_and_Nevis, - /// Republic of Korea + /// Republic of Korea. [EnumMember(Value = "KR")] Republic_of_Korea, - /// Kuwait + /// Kuwait. [EnumMember(Value = "KW")] Kuwait, - /// Cayman Islands + /// Cayman Islands. [EnumMember(Value = "KY")] Cayman_Islands, - /// Kazakhstan + /// Kazakhstan. [EnumMember(Value = "KZ")] Kazakhstan, - /// Lao People's Democratic Republic (AKA Laos) + /// Lao People's Democratic Republic. [EnumMember(Value = "LA")] Lao_People_s_Democratic_Republic, - /// Lebanon + /// Lebanon. [EnumMember(Value = "LB")] Lebanon, - /// Saint Lucia + /// Saint Lucia. [EnumMember(Value = "LC")] Saint_Lucia, - /// Liechtenstein + /// Liechtenstein. [EnumMember(Value = "LI")] Liechtenstein, - /// Sri Lanka + /// Sri Lanka. [EnumMember(Value = "LK")] Sri_Lanka, - /// Liberia + /// Liberia. [EnumMember(Value = "LR")] Liberia, - /// Lesotho + /// Lesotho. [EnumMember(Value = "LS")] Lesotho, - /// Lithuania + /// Lithuania. [EnumMember(Value = "LT")] Lithuania, - /// Luxembourg + /// Luxembourg. [EnumMember(Value = "LU")] Luxembourg, - /// Latvia + /// Latvia. [EnumMember(Value = "LV")] Latvia, - /// Libyan Arab Jamahiriya + /// Libyan Arab Jamahiriya. [EnumMember(Value = "LY")] Libyan_Arab_Jamahiriya, - /// Morocco + /// Morocco. [EnumMember(Value = "MA")] Morocco, - /// Monaco + /// Monaco. [EnumMember(Value = "MC")] Monaco, - /// Republic of Moldova + /// Republic of Moldova. [EnumMember(Value = "MD")] Republic_of_Moldova, - /// Montenegro + /// Montenegro. [EnumMember(Value = "ME")] Montenegro, - /// Saint Martin + /// Saint Martin. [EnumMember(Value = "MF")] Saint_Martin, - /// Madagascar + /// Madagascar. [EnumMember(Value = "MG")] Madagascar, - /// Marshall Islands + /// Marshall Islands. [EnumMember(Value = "MH")] Marshall_Islands, - /// The Former Yugoslav Republic of Macedonia + /// The Former Yugoslav Republic of Macedonia. [EnumMember(Value = "MK")] The_Former_Yugoslav_Republic_of_Macedonia, - /// Mali + /// Mali. [EnumMember(Value = "ML")] Mali, - /// Myanmar + /// Myanmar. [EnumMember(Value = "MM")] Myanmar, - /// Mongolia + /// Mongolia. [EnumMember(Value = "MN")] Mongolia, - /// Macau SAR/ Macao + /// Macau SAR/ Macao. [EnumMember(Value = "MO")] Macau_SAR_Macao, - /// Northern Mariana Islands + /// Northern Mariana Islands. [EnumMember(Value = "MP")] Northern_Mariana_Islands, - /// Martinique + /// Martinique. [EnumMember(Value = "MQ")] Martinique, - /// Mauritania + /// Mauritania. [EnumMember(Value = "MR")] Mauritania, - /// Montserrat + /// Montserrat. [EnumMember(Value = "MS")] Montserrat, - /// Malta + /// Malta. [EnumMember(Value = "MT")] Malta, - /// Mauritius + /// Mauritius. [EnumMember(Value = "MU")] Mauritius, - /// Maldives + /// Maldives. [EnumMember(Value = "MV")] Maldives, - /// Malawi + /// Malawi. [EnumMember(Value = "MW")] Malawi, - /// Mexico + /// Mexico. [EnumMember(Value = "MX")] Mexico, - /// Malaysia + /// Malaysia. [EnumMember(Value = "MY")] Malaysia, - /// Mozambique + /// Mozambique. [EnumMember(Value = "MZ")] Mozambique, - /// Namibia + /// Namibia. [EnumMember(Value = "NA")] Namibia, - /// New Caledonia + /// New Caledonia. [EnumMember(Value = "NC")] New_Caledonia, - /// Niger + /// Niger. [EnumMember(Value = "NE")] Niger, - /// Norfolk Island + /// Norfolk Island. [EnumMember(Value = "NF")] Norfolk_Island, - /// Nigeria + /// Nigeria. [EnumMember(Value = "NG")] Nigeria, - /// Nicaragua + /// Nicaragua. [EnumMember(Value = "NI")] Nicaragua, - /// Netherlands + /// Netherlands. [EnumMember(Value = "NL")] Netherlands, - /// Norway + /// Norway. [EnumMember(Value = "NO")] Norway, - /// Nepal + /// Nepal. [EnumMember(Value = "NP")] Nepal, - /// Nauru + /// Nauru. [EnumMember(Value = "NR")] Nauru, - /// Niue + /// Niue. [EnumMember(Value = "NU")] Niue, - /// New Zealand + /// New Zealand. [EnumMember(Value = "NZ")] New_Zealand, - /// Oman + /// Oman. [EnumMember(Value = "OM")] Oman, - /// Panama + /// Panama. [EnumMember(Value = "PA")] Panama, - /// Peru + /// Peru. [EnumMember(Value = "PE")] Peru, - /// French Polynesia + /// French Polynesia. [EnumMember(Value = "PF")] French_Polynesia, - /// Papua New Guinea + /// Papua New Guinea. [EnumMember(Value = "PG")] Papua_New_Guinea, - /// Philippines + /// Philippines. [EnumMember(Value = "PH")] Philippines, - /// Pakistan + /// Pakistan. [EnumMember(Value = "PK")] Pakistan, - /// Poland + /// Poland. [EnumMember(Value = "PL")] Poland, - /// Saint Pierre and Miquelon + /// Saint Pierre and Miquelon. [EnumMember(Value = "PM")] Saint_Pierre_and_Miquelon, - /// Puerto Rico + /// Puerto Rico. [EnumMember(Value = "PR")] Puerto_Rico, - /// Palestinian Territory, Occupied + /// Palestinian Territory, Occupied. [EnumMember(Value = "PS")] Palestinian_Territory_Occupied, - /// Portugal + /// Portugal. [EnumMember(Value = "PT")] Portugal, - /// Palau + /// Palau. [EnumMember(Value = "PW")] Palau, - /// Paraguay + /// Paraguay. [EnumMember(Value = "PY")] Paraguay, - /// Qatar + /// Qatar. [EnumMember(Value = "QA")] Qatar, - /// Reunion + /// Reunion. [EnumMember(Value = "RE")] Reunion, - /// Romania + /// Romania. [EnumMember(Value = "RO")] Romania, - /// Serbia + /// Serbia. [EnumMember(Value = "RS")] Serbia, - /// Russian Federation + /// Russian Federation. [EnumMember(Value = "RU")] Russian_Federation, - /// Rwanda + /// Rwanda. [EnumMember(Value = "RW")] Rwanda, - /// Saudi Arabia + /// Saudi Arabia. [EnumMember(Value = "SA")] Saudi_Arabia, - /// Solomon Islands + /// Solomon Islands. [EnumMember(Value = "SB")] Solomon_Islands, - /// Seychelles + /// Seychelles. [EnumMember(Value = "SC")] Seychelles, - /// Sweden + /// Sweden. [EnumMember(Value = "SE")] Sweden, - /// Singapore + /// Singapore. [EnumMember(Value = "SG")] Singapore, - /// Slovenia + /// Slovenia. [EnumMember(Value = "SI")] Slovenia, - /// Slovakia + /// Slovakia. [EnumMember(Value = "SK")] Slovakia, - /// Sierra Leone + /// Sierra Leone. [EnumMember(Value = "SL")] Sierra_Leone, - /// San Marino + /// San Marino. [EnumMember(Value = "SM")] San_Marino, - /// Senegal + /// Senegal. [EnumMember(Value = "SN")] Senegal, - /// Somalia + /// Somalia. [EnumMember(Value = "SO")] Somalia, - /// Suriname + /// Suriname. [EnumMember(Value = "SR")] Suriname, - /// South Sudan + /// South Sudan. [EnumMember(Value = "SS")] South_Sudan, - /// Sao Tome and Principe + /// Sao Tome and Principe. [EnumMember(Value = "ST")] Sao_Tome_and_Principe, - /// El Salvador + /// El Salvador. [EnumMember(Value = "SV")] El_Salvador, - /// Swaziland + /// Swaziland. [EnumMember(Value = "SZ")] Swaziland, - /// Turks and Caicos Islands + /// Turks and Caicos Islands. [EnumMember(Value = "TC")] Turks_and_Caicos_Islands, - /// Chad + /// Chad. [EnumMember(Value = "TD")] Chad, - /// French Southern Territories + /// French Southern Territories. [EnumMember(Value = "TF")] French_Southern_Territories, - /// Togo + /// Togo. [EnumMember(Value = "TG")] Togo, - /// Thailand + /// Thailand. [EnumMember(Value = "TH")] Thailand, - /// Tajikistan + /// Tajikistan. [EnumMember(Value = "TJ")] Tajikistan, - /// Tokelau + /// Tokelau. [EnumMember(Value = "TK")] Tokelau, - /// Timor-Leste + /// Timor-Leste. [EnumMember(Value = "TL")] Timor_Leste, - /// Turkmenistan + /// Turkmenistan. [EnumMember(Value = "TM")] Turkmenistan, - /// Tunisia + /// Tunisia. [EnumMember(Value = "TN")] Tunisia, - /// Tonga + /// Tonga. [EnumMember(Value = "TO")] Tonga, - /// Turkey + /// Turkey. [EnumMember(Value = "TR")] Turkey, - /// Trinidad and Tobago + /// Trinidad and Tobago. [EnumMember(Value = "TT")] Trinidad_and_Tobago, - /// Tuvalu + /// Tuvalu. [EnumMember(Value = "TV")] Tuvalu, - /// Taiwan + /// Taiwan. [EnumMember(Value = "TW")] Taiwan, - /// United Republic of Tanzania + /// United Republic of Tanzania. [EnumMember(Value = "TZ")] United_Republic_of_Tanzania, - /// Ukraine + /// Ukraine. [EnumMember(Value = "UA")] Ukraine, - /// Uganda + /// Uganda. [EnumMember(Value = "UG")] Uganda, - /// (See "GB") + /// United Kingdom. + /// See . [EnumMember(Value = "UK")] United_Kingdom, - /// United States Minor Outlying Islands + /// United States Minor Outlying Islands. [EnumMember(Value = "UM")] United_States_Minor_Outlying_Islands, - /// United States of America + /// United States of America. [EnumMember(Value = "US")] United_States_of_America, - /// Uruguay + /// Uruguay. [EnumMember(Value = "UY")] Uruguay, - /// Uzbekistan + /// Uzbekistan. [EnumMember(Value = "UZ")] Uzbekistan, - /// Holy See (Vatican City State) + /// Holy See (Vatican City State). [EnumMember(Value = "VA")] Holy_See_Vatican_City_State, - /// Saint Vincent and The Grenadines + /// Saint Vincent and The Grenadines. [EnumMember(Value = "VC")] Saint_Vincent_and_The_Grenadines, - /// Venezuela + /// Venezuela. [EnumMember(Value = "VE")] Venezuela, - /// Virgin Islands, British + /// Virgin Islands, British. [EnumMember(Value = "VG")] Virgin_Islands_British, - /// Virgin Islands, U.S. + /// Virgin Islands, U.S.. [EnumMember(Value = "VI")] - Virgin_Islands_US, + Virgin_Islands_U_S, - /// Vietnam + /// Vietnam. [EnumMember(Value = "VN")] Vietnam, - /// Vanuatu + /// Vanuatu. [EnumMember(Value = "VU")] Vanuatu, - /// Wallis and Futuna + /// Wallis and Futuna. [EnumMember(Value = "WF")] Wallis_and_Futuna, - /// Samoa + /// Samoa. [EnumMember(Value = "WS")] Samoa, - /// Yemen + /// Yemen. [EnumMember(Value = "YE")] Yemen, - /// Mayotte + /// Mayotte. [EnumMember(Value = "YT")] Mayotte, - /// South Africa + /// South Africa. [EnumMember(Value = "ZA")] South_Africa, - /// Zambia + /// Zambia. [EnumMember(Value = "ZM")] Zambia, - /// Zimbabwe + /// Zimbabwe. [EnumMember(Value = "ZW")] Zimbabwe, } diff --git a/Source/ZoomNet/Models/DashboardMeetingType.cs b/Source/ZoomNet/Models/DashboardMeetingType.cs index 27731eba..87cc3827 100644 --- a/Source/ZoomNet/Models/DashboardMeetingType.cs +++ b/Source/ZoomNet/Models/DashboardMeetingType.cs @@ -14,13 +14,13 @@ public enum DashboardMeetingType Live, /// - /// Past + /// Past. /// [EnumMember(Value = "past")] Past, /// - /// PastOne + /// PastOne. /// [EnumMember(Value = "pastOne")] PastOne diff --git a/Source/ZoomNet/Models/DataCenterRegion.cs b/Source/ZoomNet/Models/DataCenterRegion.cs index 3cfbd399..299ccfcf 100644 --- a/Source/ZoomNet/Models/DataCenterRegion.cs +++ b/Source/ZoomNet/Models/DataCenterRegion.cs @@ -7,59 +7,59 @@ namespace ZoomNet.Models /// public enum DataCenterRegion { - /// Europe + /// Europe. [EnumMember(Value = "EU")] Europe, - /// Hong Kong + /// Hong Kong. [EnumMember(Value = "HK")] HongKong, - /// Australia + /// Australia. [EnumMember(Value = "AU")] Australia, - /// India + /// India. [EnumMember(Value = "IN")] India, - /// Latin America + /// Latin America. [EnumMember(Value = "LA")] LatinAmerica, - /// Tokyo + /// Tokyo. [EnumMember(Value = "TY")] Tokyo, - /// China + /// China. [EnumMember(Value = "CN")] China, - /// United States of America + /// United States of America. [EnumMember(Value = "US")] UnitedStatesOfAmerica, - /// Canada + /// Canada. [EnumMember(Value = "CA")] Canada, - /// Canada + /// Germany. [EnumMember(Value = "DE")] Germany, - /// Canada + /// Netherlands. [EnumMember(Value = "NL")] Netherlands, - /// Mexico + /// Mexico. [EnumMember(Value = "MX")] Mexico, - /// Singapore + /// Singapore. [EnumMember(Value = "SG")] Singapore, - /// Ireland + /// Ireland. [EnumMember(Value = "IE")] Ireland, } diff --git a/Source/ZoomNet/Models/InterpretationLanguage.cs b/Source/ZoomNet/Models/InterpretationLanguage.cs index a383f32d..1d28dfa0 100644 --- a/Source/ZoomNet/Models/InterpretationLanguage.cs +++ b/Source/ZoomNet/Models/InterpretationLanguage.cs @@ -7,39 +7,39 @@ namespace ZoomNet.Models /// public enum InterpretationLanguage { - /// English + /// English. [EnumMember(Value = "English")] English, - /// Chinese + /// Chinese. [EnumMember(Value = "Chinese")] Chinese, - /// Japanese + /// Japanese. [EnumMember(Value = "Japanese")] Japanese, - /// German + /// German. [EnumMember(Value = "German")] German, - /// French + /// French. [EnumMember(Value = "French")] French, - /// Russian + /// Russian. [EnumMember(Value = "Russian")] Russian, - /// Portuguese + /// Portuguese. [EnumMember(Value = "Portuguese")] Portuguese, - /// Spanish + /// Spanish. [EnumMember(Value = "Spanish")] Spanish, - /// Korean + /// Korean. [EnumMember(Value = "Korean")] Korean } diff --git a/Source/ZoomNet/Models/Language.cs b/Source/ZoomNet/Models/Language.cs index 45ea94fb..f469d1d0 100644 --- a/Source/ZoomNet/Models/Language.cs +++ b/Source/ZoomNet/Models/Language.cs @@ -7,60 +7,60 @@ namespace ZoomNet.Models /// public enum Language { - /// English (US) + /// English (UK). + [EnumMember(Value = "en-GB")] + English_UK, + + /// English (US). [EnumMember(Value = "en-US")] English_US, - /// German (Germany) + /// Arabic. + [EnumMember(Value = "ar")] + Arabic, + + /// Danish (Denmark). + [EnumMember(Value = "da-DK")] + Danish_Denmark, + + /// German (Germany). [EnumMember(Value = "de-DE")] German_Germany, - /// Spanish (Spain) + /// Spanish (Spain). [EnumMember(Value = "es-ES")] Spanish_Spain, - /// French (France) - [EnumMember(Value = "fr-FR")] - French_France, - - /// Japanese - [EnumMember(Value = "jp-JP")] - Japanese, - - /// Portuguese (Portugal) - [EnumMember(Value = "pt-PT")] - Portuguese_Portugal, - - /// Russian - [EnumMember(Value = "ru-RU")] - Russian, + /// Spanish (Mexico). + [EnumMember(Value = "es-MX")] + Spanish_Mexico, - /// Chinese (PRC) - [EnumMember(Value = "zh-CN")] - Chinese_PRC, + /// French (Canada). + [EnumMember(Value = "fr-CA")] + French_Canada, - /// Chinese (Taiwan) - [EnumMember(Value = "zh-TW")] - Chinese_Taiwan, - - /// Korean - [EnumMember(Value = "ko-KO")] - Korean, + /// French (France). + [EnumMember(Value = "fr-FR")] + French_France, - /// Italian (Italy) + /// Italian (Italy). [EnumMember(Value = "it-IT")] Italian_Italy, - /// Vietnamese - [EnumMember(Value = "vi-VN")] - Vietnamese, + /// Japanese. + [EnumMember(Value = "ja")] + Japanese, + + /// Korean (Korea). + [EnumMember(Value = "ko-KR")] + Korean_Korea, - /// Polish - [EnumMember(Value = "pl-PL")] - Polish, + /// Dutch (Netherlands). + [EnumMember(Value = "nl-NL")] + Dutch_Netherlands, - /// Turkish - [EnumMember(Value = "Tr-TR")] - Turkish, + /// Portuguese (Brazil). + [EnumMember(Value = "pt-BR")] + Portuguese_Brazil, } } diff --git a/Source/ZoomNet/Models/MeetingType.cs b/Source/ZoomNet/Models/MeetingType.cs index d597cc02..a986f3e6 100644 --- a/Source/ZoomNet/Models/MeetingType.cs +++ b/Source/ZoomNet/Models/MeetingType.cs @@ -26,7 +26,7 @@ public enum MeetingType Personal = 4, /// - /// A PAC (Personal Audio Conference) meeting + /// A PAC (Personal Audio Conference) meeting. /// PersonalAudioConference = 7, diff --git a/Source/ZoomNet/Models/NumberOfEmployees.cs b/Source/ZoomNet/Models/NumberOfEmployees.cs index bc7c185c..64496afe 100644 --- a/Source/ZoomNet/Models/NumberOfEmployees.cs +++ b/Source/ZoomNet/Models/NumberOfEmployees.cs @@ -7,39 +7,39 @@ namespace ZoomNet.Models /// public enum NumberOfEmployees { - /// Unknown + /// Unknown. [EnumMember(Value = "")] Unknown, - /// 1-20 + /// 1-20. [EnumMember(Value = "1-20")] Between_0001_and_0020, - /// 21-50 + /// 21-50. [EnumMember(Value = "21-50")] Between_0021_and_0050, - /// 21-50 + /// 21-50. [EnumMember(Value = "51-100")] Between_0051_and_0100, - /// 101-500 + /// 101-500. [EnumMember(Value = "101-500")] Between_0101_and_0500, - /// 501-1,000 + /// 501-1,000. [EnumMember(Value = "501-1,000")] // There's a typo in the documentation: it says 500-1,000 but the API rejects that value. The actual value is 501-1,000 Between_0501_and_1000, - /// 21-50 + /// 21-50. [EnumMember(Value = "1,001-5,000")] Between_1001_and_5000, - /// 5,001-10,000 + /// 5,001-10,000. [EnumMember(Value = "5,001-10,000")] Between_5001_and_10000, - /// 5,001-10,000 + /// 5,001-10,000. [EnumMember(Value = "More than 10,000")] More_than_10000, } diff --git a/Source/ZoomNet/Models/PresenceStatus.cs b/Source/ZoomNet/Models/PresenceStatus.cs index c0fecba1..abf9b5d4 100644 --- a/Source/ZoomNet/Models/PresenceStatus.cs +++ b/Source/ZoomNet/Models/PresenceStatus.cs @@ -10,7 +10,7 @@ public enum PresenceStatus /// /// Unknown. /// - /// Default value + /// Default value. Unknown, /// diff --git a/Source/ZoomNet/Models/PurchasingTimeFrame.cs b/Source/ZoomNet/Models/PurchasingTimeFrame.cs index f3e7c1f5..bf9fbdc8 100644 --- a/Source/ZoomNet/Models/PurchasingTimeFrame.cs +++ b/Source/ZoomNet/Models/PurchasingTimeFrame.cs @@ -7,27 +7,27 @@ namespace ZoomNet.Models /// public enum PurchasingTimeFrame { - /// Unknown + /// Unknown. [EnumMember(Value = "")] Unknown, - /// Within a month + /// Within a month. [EnumMember(Value = "Within a month")] Within_a_month, - /// 1-3 months + /// 1-3 months. [EnumMember(Value = "1-3 months")] Between_1_and_3_months, - /// 4-6 months + /// 4-6 months. [EnumMember(Value = "4-6 months")] Between_4_and_6_months, - /// More than 6 months + /// More than 6 months. [EnumMember(Value = "More than 6 months")] More_than_6_months, - /// More than 6 months + /// More than 6 months. [EnumMember(Value = "No timeframe")] No_timeframe, } diff --git a/Source/ZoomNet/Models/RecordingFileType.cs b/Source/ZoomNet/Models/RecordingFileType.cs index 447b4e7d..8fc4c71c 100644 --- a/Source/ZoomNet/Models/RecordingFileType.cs +++ b/Source/ZoomNet/Models/RecordingFileType.cs @@ -40,7 +40,7 @@ public enum RecordingFileType [EnumMember(Value = "csv")] PollingData, - /// Summary file of the recording in JSON file format + /// Summary file of the recording in JSON file format. [EnumMember(Value = "summary")] Summary, } diff --git a/Source/ZoomNet/Models/RoleInPurchaseProcess.cs b/Source/ZoomNet/Models/RoleInPurchaseProcess.cs index 8b24262d..72292567 100644 --- a/Source/ZoomNet/Models/RoleInPurchaseProcess.cs +++ b/Source/ZoomNet/Models/RoleInPurchaseProcess.cs @@ -7,23 +7,23 @@ namespace ZoomNet.Models /// public enum RoleInPurchaseProcess { - /// Unknown + /// Unknown. [EnumMember(Value = "")] Unknown, - /// Decision Maker + /// Decision Maker. [EnumMember(Value = "Decision Maker")] Decision_Maker, - /// Evaluator/Recommender + /// Evaluator/Recommender. [EnumMember(Value = "Evaluator/Recommender")] Evaluator_or_Recommender, - /// Influencer + /// Influencer. [EnumMember(Value = "Influencer")] Influencer, - /// Not Involved + /// Not Involved. [EnumMember(Value = "Not involved")] Not_Involved, } diff --git a/Source/ZoomNet/Models/StreamingService.cs b/Source/ZoomNet/Models/StreamingService.cs index af86b191..253d7df4 100644 --- a/Source/ZoomNet/Models/StreamingService.cs +++ b/Source/ZoomNet/Models/StreamingService.cs @@ -7,19 +7,19 @@ namespace ZoomNet.Models /// public enum StreamingService { - /// Facebook + /// Facebook. [EnumMember(Value = "facebook")] Facebook, - /// Workplace by Facebook + /// Workplace by Facebook. [EnumMember(Value = "workplace_by_facebook")] WorkplaceByFacebook, - /// YouTube + /// YouTube. [EnumMember(Value = "youtube")] YouTube, - /// custom live streaming service + /// custom live streaming service. [EnumMember(Value = "custom_live_streaming_service")] Custom } diff --git a/Source/ZoomNet/Models/VirtualBackgroundType.cs b/Source/ZoomNet/Models/VirtualBackgroundType.cs index 827f983b..a69dfedb 100644 --- a/Source/ZoomNet/Models/VirtualBackgroundType.cs +++ b/Source/ZoomNet/Models/VirtualBackgroundType.cs @@ -7,11 +7,11 @@ namespace ZoomNet.Models /// public enum VirtualBackgroundType { - /// Image + /// Image. [EnumMember(Value = "image")] Image, - /// Video + /// Video. [EnumMember(Value = "video")] Video } From 91bc7b96ae636b4184703123212076ed55ebadd8 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 11:18:25 -0500 Subject: [PATCH 16/22] Add a comment in code sample --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 85b96cb5..aec32a4b 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,9 @@ var refreshToken = Environment.GetEnvironmentVariable("ZOOM_OAUTH_REFRESHTOKEN", var connectionInfo = new OAuthConnectionInfo(clientId, clientSecret, refreshToken, null, (newRefreshToken, newAccessToken) => { + /* + As previously stated, it's important to preserve the refresh token. + */ Environment.SetEnvironmentVariable("ZOOM_OAUTH_REFRESHTOKEN", newRefreshToken, EnvironmentVariableTarget.User); }); var zoomClient = new ZoomClient(connectionInfo); From f293670afe80cbfc8e2bae1ae8a97e3c20de95f0 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 11:23:30 -0500 Subject: [PATCH 17/22] Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index aec32a4b..b80fb708 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,7 @@ var connectionInfo = new OAuthConnectionInfo(clientId, clientSecret, accountId, /* Server-to-Server OAuth does not use a refresh token. That's why I used '_' as the first parameter in this delegate declaration. Furthermore, ZoomNet will take care of getting a new access token - and to refresh it whenever it expires therefore there is no need for you to preserve the token. + and to refresh it whenever it expires therefore there is no need for you to preserve it. In fact, this delegate is completely optional when using Server-to-Server OAuth. Feel free to pass a null value in lieu of a delegate. From 161dd2f5207e2bec3b18d14d97dd5c79b470a4c4 Mon Sep 17 00:00:00 2001 From: jericho Date: Thu, 22 Dec 2022 16:02:25 -0500 Subject: [PATCH 18/22] Fix the problem with Authorization missing when redirect Resolves #257 --- .../ZoomNet/Utilities/ZoomRetryCoordinator.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs b/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs index 763a7cb6..e8afc212 100644 --- a/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs +++ b/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs @@ -13,7 +13,7 @@ namespace ZoomNet.Utilities /// A request coordinator which retries failed requests with a delay between each attempt. internal class ZoomRetryCoordinator : IRequestCoordinator { - private static readonly ReaderWriterLockSlim _lock = new ReaderWriterLockSlim(); + private static readonly ReaderWriterLockSlim _lock = new(); private readonly IRequestCoordinator _defaultRetryCoordinator; private readonly ITokenHandler _tokenHandler; @@ -57,6 +57,8 @@ public ZoomRetryCoordinator(IEnumerable config, ITokenHandler toke /// The final HTTP response. public async Task ExecuteAsync(IRequest request, Func> dispatcher) { + var requestUri = request.Message.RequestUri; + // Dispatch the request var response = await _defaultRetryCoordinator.ExecuteAsync(request, dispatcher).ConfigureAwait(false); @@ -73,6 +75,21 @@ public async Task ExecuteAsync(IRequest request, Func Date: Thu, 22 Dec 2022 16:06:10 -0500 Subject: [PATCH 19/22] Fix SA1414 Tuple types in signatures should have element names --- Source/ZoomNet/Extensions/Internal.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index 3885323c..19910bea 100644 --- a/Source/ZoomNet/Extensions/Internal.cs +++ b/Source/ZoomNet/Extensions/Internal.cs @@ -649,7 +649,7 @@ internal static (WeakReference RequestReference, string Diag return diagnosticInfo; } - internal static async Task<(bool, string, int?)> GetErrorMessageAsync(this HttpResponseMessage message) + internal static async Task<(bool IsError, string ErrorMessage, int? ErrorCode)> GetErrorMessageAsync(this HttpResponseMessage message) { // Default error code int? errorCode = null; From 19de250f5e70148f813bd7a6594be53b32e61e8c Mon Sep 17 00:00:00 2001 From: jericho Date: Fri, 23 Dec 2022 10:05:43 -0500 Subject: [PATCH 20/22] Fix CA2016 Forward the 'cancellationToken' parameter --- Source/ZoomNet/Extensions/Internal.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index 19910bea..886e04d8 100644 --- a/Source/ZoomNet/Extensions/Internal.cs +++ b/Source/ZoomNet/Extensions/Internal.cs @@ -161,8 +161,11 @@ internal static async Task ReadAsStringAsync(this HttpContent httpConten if (httpContent != null) { +#if NET5_0_OR_GREATER + var contentStream = await httpContent.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); +#else var contentStream = await httpContent.ReadAsStreamAsync().ConfigureAwait(false); - +#endif encoding ??= httpContent.GetEncoding(Encoding.UTF8); // This is important: we must make a copy of the response stream otherwise we would get an @@ -174,7 +177,11 @@ internal static async Task ReadAsStringAsync(this HttpContent httpConten ms.Position = 0; using (var sr = new StreamReader(ms, encoding)) { +#if NET7_0_OR_GREATER + content = await sr.ReadToEndAsync(cancellationToken).ConfigureAwait(false); +#else content = await sr.ReadToEndAsync().ConfigureAwait(false); +#endif } // It's important to rewind the stream From 450f6648dcf586179a4ee09f76694ea43271b882 Mon Sep 17 00:00:00 2001 From: jericho Date: Fri, 23 Dec 2022 10:18:18 -0500 Subject: [PATCH 21/22] Retry coordinator does not need to check for errors if the request was successful --- Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs b/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs index e8afc212..29dc87c0 100644 --- a/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs +++ b/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs @@ -61,6 +61,7 @@ public async Task ExecuteAsync(IRequest request, Func Date: Fri, 23 Dec 2022 10:41:43 -0500 Subject: [PATCH 22/22] Refresh build script --- build.cake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index 99374a2d..3efa377d 100644 --- a/build.cake +++ b/build.cake @@ -2,13 +2,13 @@ #tool dotnet:?package=GitVersion.Tool&version=5.11.1 #tool dotnet:?package=coveralls.net&version=4.0.1 #tool nuget:?package=GitReleaseManager&version=0.13.0 -#tool nuget:?package=ReportGenerator&version=5.1.12 +#tool nuget:?package=ReportGenerator&version=5.1.13 #tool nuget:?package=xunit.runner.console&version=2.4.2 #tool nuget:?package=Codecov&version=1.13.0 // Install addins. #addin nuget:?package=Cake.Coveralls&version=1.1.0 -#addin nuget:?package=Cake.Git&version=2.0.0 +#addin nuget:?package=Cake.Git&version=3.0.0 #addin nuget:?package=Cake.Codecov&version=1.0.1