diff --git a/README.md b/README.md index 3d906479..b80fb708 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 @@ -113,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); @@ -137,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. @@ -158,7 +163,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 { @@ -167,10 +171,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 ... @@ -197,8 +200,6 @@ The `WebhookParser` class has a method called `VerifyAndParseEventWebhookAsync`w ```csharp using Microsoft.AspNetCore.Mvc; -using StrongGrid; -using System.Security; namespace WebApplication1.Controllers { @@ -209,28 +210,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... - // 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 + return Ok(); + } + } +} +``` + +### Responding to requests from Zoom to validate your webhook endpoint - // 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); +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 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: - // ... 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 ..."; + + 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); + } + } +} +``` + +### The ultimate webhook controller + +Here's the "ultimate" webhook controller which combines all the above features: + +```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 +``` 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() { 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.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 - + diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index 0dd8072d..886e04d8 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 @@ -161,9 +161,12 @@ 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); - - if (encoding == null) encoding = httpContent.GetEncoding(Encoding.UTF8); +#endif + 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 @@ -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 @@ -649,7 +656,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; diff --git a/Source/ZoomNet/Json/WebhookEventConverter.cs b/Source/ZoomNet/Json/WebhookEventConverter.cs index 560438d6..2efea824 100644 --- a/Source/ZoomNet/Json/WebhookEventConverter.cs +++ b/Source/ZoomNet/Json/WebhookEventConverter.cs @@ -269,6 +269,10 @@ 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); + webHookEvent = endpointUrlValidationEvent; + break; default: throw new Exception($"{eventType} is an unknown event type"); } diff --git a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs index 36a48901..ef60d8b8 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))] @@ -171,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")] @@ -360,6 +362,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[]))] @@ -394,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")] @@ -503,6 +507,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?))] 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/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/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 } diff --git a/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs new file mode 100644 index 00000000..4f252954 --- /dev/null +++ b/Source/ZoomNet/Models/Webhooks/EndpointUrlValidationEvent.cs @@ -0,0 +1,42 @@ +using System.Security.Cryptography; +using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; +using System.Text.Json.Serialization; +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. + /// + [JsonPropertyName("plainToken")] + 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.ASCII.GetBytes(secretToken)); + var encryptedToken = crypto.ComputeHash(Encoding.ASCII.GetBytes(this.PlainToken)).ToHexString(); + + var data = new JsonObject + { + { "plainToken", this.PlainToken }, + { "encryptedToken", encryptedToken }, + }; + + var jsonString = JsonSerializer.Serialize(data, typeof(JsonObject), JsonFormatter.SerializationContext); + return jsonString; + } + } +} 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, } } 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..f1df1cc0 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(from)}."); + } + + 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"); + } } } diff --git a/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs b/Source/ZoomNet/Utilities/ZoomRetryCoordinator.cs index 763a7cb6..29dc87c0 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,8 +57,11 @@ 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); + if (response.IsSuccessStatusCode) return response; // Check if the token needs to be refreshed if (response.StatusCode == HttpStatusCode.Unauthorized) @@ -73,6 +76,21 @@ public async Task ExecuteAsync(IRequest request, Func - + 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