From ed3624a19cc4cfc26215258f8e79ea813053c72c Mon Sep 17 00:00:00 2001 From: jericho Date: Tue, 12 Dec 2023 12:05:36 -0500 Subject: [PATCH 1/5] Unit tests from ToUnixTime and FromUnixTime --- .../Extensions/InternalTests.cs | 100 ++++++++++++++++++ Source/ZoomNet/Extensions/Internal.cs | 4 +- 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs b/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs index 6480af1b..99f7fd87 100644 --- a/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs +++ b/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs @@ -10,11 +10,111 @@ using Xunit; using ZoomNet.Models; using ZoomNet.Utilities; +using static ZoomNet.Internal; namespace ZoomNet.UnitTests.Extensions { public class InternalTests { + public class FromUnixTime + { + // Note to self: + // I'm using TheoryData because can't use DateTime with InlineData: + // Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + public static TheoryData FromMilliseconds = new TheoryData() + { + { 0, new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 1000, new DateTime(1970, 1, 1, 0, 0, 1, 0, DateTimeKind.Utc) }, + { 16040, new DateTime(1970, 1, 1, 0, 0, 16, 40, DateTimeKind.Utc) }, + }; + + public static TheoryData FromSeconds = new TheoryData() + { + { 0, new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc) }, + { 1000, new DateTime(1970, 1, 1, 0, 16, 40, 0, DateTimeKind.Utc) }, + }; + + [Theory, MemberData(nameof(FromMilliseconds))] + public void Converts_from_milliseconds(long numberOfMilliseconds, DateTime expected) + { + // Act + var result = numberOfMilliseconds.FromUnixTime(UnixTimePrecision.Milliseconds); + + // Assert + result.ShouldBe(expected); + } + + [Theory, MemberData(nameof(FromSeconds))] + public void Converts_from_seconds(long numberOfSeconds, DateTime expected) + { + // Act + var result = numberOfSeconds.FromUnixTime(UnixTimePrecision.Seconds); + + // Assert + result.ShouldBe(expected); + } + + [Fact] + public void Throws_when_unknown_precision() + { + // Arrange + var unknownPrecision = (UnixTimePrecision)3; + + // Act + Should.Throw(() => 123L.FromUnixTime(unknownPrecision)); + } + } + + public class ToUnixTime + { + // Note to self: + // I'm using TheoryData because can't use DateTime with InlineData: + // Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + public static TheoryData ToMilliseconds = new TheoryData() + { + { new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), 0 }, + { new DateTime(1970, 1, 1, 0, 0, 1, 0, DateTimeKind.Utc), 1000 }, + { new DateTime(1970, 1, 1, 0, 0, 16, 40, DateTimeKind.Utc), 16040 }, + }; + + public static TheoryData ToSeconds = new TheoryData() + { + { new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc), 0 }, + { new DateTime(1970, 1, 1, 0, 0, 1, 0, DateTimeKind.Utc), 1 }, + { new DateTime(1970, 1, 1, 0, 0, 16, 40, DateTimeKind.Utc), 16 }, + }; + + [Theory, MemberData(nameof(ToMilliseconds))] + public void Converts_to_milliseconds(DateTime date, long expected) + { + // Act + var result = date.ToUnixTime(UnixTimePrecision.Milliseconds); + + // Assert + result.ShouldBe(expected); + } + + [Theory, MemberData(nameof(ToSeconds))] + public void Converts_to_seconds(DateTime date, long expected) + { + // Act + var result = date.ToUnixTime(UnixTimePrecision.Seconds); + + // Assert + result.ShouldBe(expected); + } + + [Fact] + public void Throws_when_unknown_precision() + { + // Arrange + var unknownPrecision = (UnixTimePrecision)3; + + // Act + Should.Throw(() => DateTime.UtcNow.ToUnixTime(unknownPrecision)); + } + } + public class AsPaginatedResponse { [Fact] diff --git a/Source/ZoomNet/Extensions/Internal.cs b/Source/ZoomNet/Extensions/Internal.cs index f0e50333..79ee3779 100644 --- a/Source/ZoomNet/Extensions/Internal.cs +++ b/Source/ZoomNet/Extensions/Internal.cs @@ -51,7 +51,7 @@ internal static DateTime FromUnixTime(this long unixTime, UnixTimePrecision prec { if (precision == UnixTimePrecision.Seconds) return EPOCH.AddSeconds(unixTime); if (precision == UnixTimePrecision.Milliseconds) return EPOCH.AddMilliseconds(unixTime); - throw new Exception($"Unknown precision: {precision}"); + throw new ArgumentException($"Unknown precision: {precision}"); } /// @@ -68,7 +68,7 @@ internal static long ToUnixTime(this DateTime date, UnixTimePrecision precision var diff = date.ToUniversalTime() - EPOCH; if (precision == UnixTimePrecision.Seconds) return Convert.ToInt64(diff.TotalSeconds); if (precision == UnixTimePrecision.Milliseconds) return Convert.ToInt64(diff.TotalMilliseconds); - throw new Exception($"Unknown precision: {precision}"); + throw new ArgumentException($"Unknown precision: {precision}"); } /// From 60bd1644c13c016f52daa0f893fd28b86e66af67 Mon Sep 17 00:00:00 2001 From: jericho Date: Tue, 12 Dec 2023 14:31:28 -0500 Subject: [PATCH 2/5] Add unit tests for ToZoomFormat() --- .../Extensions/InternalTests.cs | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs b/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs index 99f7fd87..52bc49d6 100644 --- a/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs +++ b/Source/ZoomNet.UnitTests/Extensions/InternalTests.cs @@ -115,6 +115,62 @@ public void Throws_when_unknown_precision() } } + public class ToZoomFormat + { + // Note to self: + // I'm using TheoryData because can't use DateTime with InlineData: + // Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + public static TheoryData SampleUtcDates = new TheoryData() + { + { new DateTime(2023, 12, 12, 12, 14, 0, 0, DateTimeKind.Utc), "2023-12-12", "2023-12-12T12:14:00Z" }, + }; + + [Theory, MemberData(nameof(SampleUtcDates))] + public void Successfully_converts_UTC_to_string(DateTime date, string expectedDateOnly, string expectedWithTime) + { + // Act + var resultDateOnly = date.ToZoomFormat(TimeZones.UTC, true); + var resultWithTime = date.ToZoomFormat(TimeZones.UTC, false); + + // Assert + resultDateOnly.ShouldBe(expectedDateOnly); + resultWithTime.ShouldBe(expectedWithTime); + } + + // Note to self: + // I'm using TheoryData because can't use DateTime with InlineData: + // Error CS0182 An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type + public static TheoryData SampleLocalDates = new TheoryData() + { + { new DateTime(2023, 12, 12, 12, 14, 0, 0, DateTimeKind.Local), "2023-12-12", "2023-12-12T12:14:00" }, + }; + + [Theory, MemberData(nameof(SampleLocalDates))] + public void Successfully_converts_Local_to_string(DateTime date, string expectedDateOnly, string expectedWithTime) + { + // Act + var resultDateOnly = date.ToZoomFormat(TimeZones.America_Montreal, true); + var resultWithTime = date.ToZoomFormat(TimeZones.America_Montreal, false); + + // Assert + resultDateOnly.ShouldBe(expectedDateOnly); + resultWithTime.ShouldBe(expectedWithTime); + } + + [Fact] + public void Returns_null_when_null() + { + // Arrange + var date = (DateTime?)null; + + // Act + var result = date.ToZoomFormat(); + + // Assert + result.ShouldBeNull(); + } + } + public class AsPaginatedResponse { [Fact] From 150d728b1c958bf649faa14373def83dec52728e Mon Sep 17 00:00:00 2001 From: joshrogers-pg <137331170+joshrogers-pg@users.noreply.github.com> Date: Fri, 19 Jan 2024 15:14:14 -0600 Subject: [PATCH 3/5] Adding support for retrieving the user profile for a Zoom Phone user. (#331) * Adding support for retrieving the user profile for a Zoom Phone user. * Adjusting for PR feedback by Pascal casing the property names of the call plan types and changing the enum values to make more sense. --- .../Models/PhoneCallUserProfileTests.cs | 292 +++++++++++++ .../Resources/PhoneCallUserProfileTests.cs | 44 ++ .../Json/ZoomNetJsonSerializerContext.cs | 6 + Source/ZoomNet/Models/CallingPlan.cs | 34 ++ Source/ZoomNet/Models/CallingPlanType.cs | 387 ++++++++++++++++++ Source/ZoomNet/Models/EmergencyAddress.cs | 51 +++ Source/ZoomNet/Models/PhoneCallPhoneNumber.cs | 27 ++ Source/ZoomNet/Models/PhoneCallUserProfile.cs | 87 ++++ Source/ZoomNet/Models/PhoneCallUserStatus.cs | 21 + Source/ZoomNet/Resources/IPhone.cs | 13 + Source/ZoomNet/Resources/Phone.cs | 13 + 11 files changed, 975 insertions(+) create mode 100644 Source/ZoomNet.UnitTests/Models/PhoneCallUserProfileTests.cs create mode 100644 Source/ZoomNet.UnitTests/Resources/PhoneCallUserProfileTests.cs create mode 100644 Source/ZoomNet/Models/CallingPlan.cs create mode 100644 Source/ZoomNet/Models/CallingPlanType.cs create mode 100644 Source/ZoomNet/Models/EmergencyAddress.cs create mode 100644 Source/ZoomNet/Models/PhoneCallPhoneNumber.cs create mode 100644 Source/ZoomNet/Models/PhoneCallUserProfile.cs create mode 100644 Source/ZoomNet/Models/PhoneCallUserStatus.cs diff --git a/Source/ZoomNet.UnitTests/Models/PhoneCallUserProfileTests.cs b/Source/ZoomNet.UnitTests/Models/PhoneCallUserProfileTests.cs new file mode 100644 index 00000000..c64ea1a9 --- /dev/null +++ b/Source/ZoomNet.UnitTests/Models/PhoneCallUserProfileTests.cs @@ -0,0 +1,292 @@ +using System.Text.Json; +using Shouldly; +using Xunit; +using ZoomNet.Json; +using ZoomNet.Models; + +namespace ZoomNet.UnitTests.Models +{ + public class PhoneCallUserProfileTests + { + #region constants + + internal const string PHONE_CALL_USER_PROFILE = @"{ + ""calling_plans"": [ + { + ""type"": 600, + ""billing_account_id"": ""3WWAEiEjTj2IQuyDiKMd_A"", + ""billing_account_name"": ""Delhi billing"" + } + ], + ""cost_center"": ""testCostCenter"", + ""department"": ""testDepartment"", + ""email"": ""suesu_test_delete3@testapi.com"", + ""emergency_address"": { + ""address_line1"": ""55 Almaden Boulevard"", + ""address_line2"": ""1002 Airport Way S"", + ""city"": ""SAN JOSE"", + ""country"": ""US"", + ""id"": ""CCc8zYT1SN60i7uDMzDbXA"", + ""state_code"": ""CA"", + ""zip"": ""95113"" + }, + ""extension_id"": ""nNGsNx2zRDyiIXWVI23FCQ"", + ""extension_number"": 100012347, + ""id"": ""NL3cEpSdRc-c2t8aLoZqiw"", + ""phone_numbers"": [ + { + ""id"": ""---M1padRvSUtw7YihN7sA"", + ""number"": ""14232058798"" + } + ], + ""phone_user_id"": ""u7pnC468TaS46OuNoEw6GA"", + ""policy"": { + ""ad_hoc_call_recording"": { + ""enable"": true, + ""recording_start_prompt"": true, + ""recording_transcription"": true, + ""play_recording_beep_tone"": { + ""enable"": true, + ""play_beep_volume"": 60, + ""play_beep_time_interval"": 15, + ""play_beep_member"": ""allMember"" + }, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""ad_hoc_call_recording_access_members"": [ + { + ""access_user_id"": ""w0RChiauQeqRlv5fgxYULQ"", + ""allow_delete"": false, + ""allow_download"": false, + ""shared_id"": ""--e8ugg0SeS-9clgrDkn2w"" + } + ], + ""auto_call_recording"": { + ""allow_stop_resume_recording"": true, + ""disconnect_on_recording_failure"": true, + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""recording_calls"": ""inbound"", + ""recording_explicit_consent"": true, + ""recording_start_prompt"": true, + ""recording_transcription"": true, + ""play_recording_beep_tone"": { + ""enable"": true, + ""play_beep_volume"": 60, + ""play_beep_time_interval"": 15, + ""play_beep_member"": ""allMember"" + } + }, + ""auto_call_recording_access_members"": [ + { + ""access_user_id"": ""w0RChiauQeqRlv5fgxYULQ"", + ""allow_delete"": false, + ""allow_download"": false, + ""shared_id"": ""--e8ugg0SeS-9clgrDkn2w"" + } + ], + ""call_overflow"": { + ""call_overflow_type"": 1, + ""enable"": true, + ""locked"": true, + ""locked_by"": ""site"", + ""modified"": true + }, + ""call_park"": { + ""call_not_picked_up_action"": 9, + ""enable"": true, + ""expiration_period"": 10, + ""forward_to"": { + ""display_name"": ""test extension name"", + ""extension_id"": ""CcrEGgmeQem1uyJsuIRKwA"", + ""extension_number"": 1000123477, + ""extension_type"": ""user"", + ""id"": ""fWOgOALdT1ei4vjXK-QYsA"" + }, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""call_transferring"": { + ""call_transferring_type"": 2, + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""delegation"": true, + ""elevate_to_meeting"": true, + ""emergency_address_management"": { + ""enable"": true, + ""prompt_default_address"": true + }, + ""emergency_calls_to_psap"": true, + ""call_handling_forwarding_to_other_users"": { + ""enable"": true, + ""call_forwarding_type"": 1, + ""locked"": true, + ""locked_by"": ""site"", + ""modified"": true + }, + ""hand_off_to_room"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""international_calling"": true, + ""mobile_switch_to_carrier"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""select_outbound_caller_id"": { + ""enable"": true, + ""allow_hide_outbound_caller_id"": true, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""sms"": { + ""enable"": true, + ""international_sms"": true, + ""international_sms_countries"": [ + ""US"" + ], + ""locked"": true, + ""locked_by"": ""account"" + }, + ""voicemail"": { + ""allow_delete"": true, + ""allow_download"": true, + ""allow_transcription"": true, + ""allow_videomail"": true, + ""enable"": true + }, + ""voicemail_access_members"": [ + { + ""access_user_id"": ""w0RChiauQeqRlv5fgxYULQ"", + ""allow_delete"": false, + ""allow_download"": false, + ""allow_sharing"": false, + ""shared_id"": ""--e8ugg0SeS-9clgrDkn2w"" + } + ], + ""zoom_phone_on_mobile"": { + ""allow_calling_sms_mms"": true, + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"" + }, + ""personal_audio_library"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true, + ""allow_music_on_hold_customization"": true, + ""allow_voicemail_and_message_greeting_customization"": true + }, + ""voicemail_transcription"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""voicemail_notification_by_email"": { + ""include_voicemail_file"": true, + ""include_voicemail_transcription"": false, + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""shared_voicemail_notification_by_email"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""check_voicemails_over_phone"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""audio_intercom"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""peer_to_peer_media"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""account"", + ""modified"": true + }, + ""e2e_encryption"": { + ""enable"": true, + ""locked"": true, + ""locked_by"": ""site"", + ""modified"": true + }, + ""outbound_calling"": { + ""enable"": true, + ""locked"": true, + ""modified"": true + }, + ""outbound_sms"": { + ""enable"": true, + ""locked"": true, + ""modified"": true + } + }, + ""site_admin"": true, + ""site_id"": ""8f71O6rWT8KFUGQmJIFAdQ"", + ""status"": ""activate"" + }"; + + #endregion + + #region tests + + [Fact] + public void Parse_Json_PhoneCallUserProfile() + { + // Arrange + + // Act + var result = JsonSerializer.Deserialize( + PHONE_CALL_USER_PROFILE, JsonFormatter.SerializerOptions); + + // Assert + result.CallingPlans.ShouldNotBeNull(); + result.CallingPlans.ShouldNotBeEmpty(); + result.CallingPlans[0].Type.ShouldBe(CallingPlanType.Beta); + result.CallingPlans[0].BillingAccountId.ShouldBe("3WWAEiEjTj2IQuyDiKMd_A"); + result.CallingPlans[0].BillingAccountName.ShouldBe("Delhi billing"); + result.CostCenter.ShouldBe("testCostCenter"); + result.Department.ShouldBe("testDepartment"); + result.Email.ShouldBe("suesu_test_delete3@testapi.com"); + result.EmergencyAddress.ShouldNotBeNull(); + result.EmergencyAddress.AddressLine1.ShouldBe("55 Almaden Boulevard"); + result.EmergencyAddress.AddressLine2.ShouldBe("1002 Airport Way S"); + result.EmergencyAddress.City.ShouldBe("SAN JOSE"); + result.EmergencyAddress.Country.ShouldBe("US"); + result.EmergencyAddress.Id.ShouldBe("CCc8zYT1SN60i7uDMzDbXA"); + result.EmergencyAddress.StateCode.ShouldBe("CA"); + result.EmergencyAddress.Zip.ShouldBe("95113"); + result.ExtensionId.ShouldBe("nNGsNx2zRDyiIXWVI23FCQ"); + result.ExtensionNumber.ShouldBe(100012347); + result.Id.ShouldBe("NL3cEpSdRc-c2t8aLoZqiw"); + result.PhoneNumbers.ShouldNotBeNull(); + result.PhoneNumbers.ShouldNotBeEmpty(); + result.PhoneNumbers[0].PhoneNumberId.ShouldBe("---M1padRvSUtw7YihN7sA"); + result.PhoneNumbers[0].PhoneNumber.ShouldBe("14232058798"); + result.PhoneUserId.ShouldBe("u7pnC468TaS46OuNoEw6GA"); + result.SiteAdmin.ShouldBeTrue(); + result.SiteId.ShouldBe("8f71O6rWT8KFUGQmJIFAdQ"); + result.Status.ShouldBe(PhoneCallUserStatus.Active); + } + + #endregion + } +} diff --git a/Source/ZoomNet.UnitTests/Resources/PhoneCallUserProfileTests.cs b/Source/ZoomNet.UnitTests/Resources/PhoneCallUserProfileTests.cs new file mode 100644 index 00000000..c1e44131 --- /dev/null +++ b/Source/ZoomNet.UnitTests/Resources/PhoneCallUserProfileTests.cs @@ -0,0 +1,44 @@ +using System.Net.Http; +using System.Threading; +using System.Threading.Tasks; +using RichardSzalay.MockHttp; +using Shouldly; +using Xunit; +using ZoomNet.Resources; + +namespace ZoomNet.UnitTests.Resources +{ + public class PhoneCallUserProfileTests + { + [Fact] + public async Task GetPhoneCallUserProfileAsync() + { + // Arrange + string userId = "NL3cEpSdRc-c2t8aLoZqiw"; + + var mockHttp = new MockHttpMessageHandler(); + mockHttp + .Expect( + HttpMethod.Get, + Utils.GetZoomApiUri("phone/users/", userId)) + .Respond( + "application/json", + Models.PhoneCallUserProfileTests.PHONE_CALL_USER_PROFILE); + + var client = Utils.GetFluentClient(mockHttp); + var phone = new Phone(client); + + // Act + var result = await phone + .GetPhoneCallUserProfileAsync(userId, CancellationToken.None) + .ConfigureAwait(true); + + // Assert + mockHttp.VerifyNoOutstandingExpectation(); + mockHttp.VerifyNoOutstandingRequest(); + result.ShouldNotBeNull(); + result.Id.ShouldNotBeNull(); + result.Id.ShouldBe(userId); + } + } +} diff --git a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs index b3b958f1..e9c2959e 100644 --- a/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs +++ b/Source/ZoomNet/Json/ZoomNetJsonSerializerContext.cs @@ -88,6 +88,7 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.DashboardParticipantQos))] [JsonSerializable(typeof(ZoomNet.Models.DataCenterRegion))] [JsonSerializable(typeof(ZoomNet.Models.EmailNotificationUserSettings))] + [JsonSerializable(typeof(ZoomNet.Models.EmergencyAddress))] [JsonSerializable(typeof(ZoomNet.Models.EncryptionType))] [JsonSerializable(typeof(ZoomNet.Models.FeatureUserSettings))] [JsonSerializable(typeof(ZoomNet.Models.ImMetric))] @@ -303,6 +304,8 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.BatchRegistrant[]))] [JsonSerializable(typeof(ZoomNet.Models.BatchRegistrantInfo[]))] [JsonSerializable(typeof(ZoomNet.Models.CalendarIntegrationType[]))] + [JsonSerializable(typeof(ZoomNet.Models.CallingPlan[]))] + [JsonSerializable(typeof(ZoomNet.Models.CallingPlanType[]))] [JsonSerializable(typeof(ZoomNet.Models.CallLog[]))] [JsonSerializable(typeof(ZoomNet.Models.CallLogCalleeNumberType[]))] [JsonSerializable(typeof(ZoomNet.Models.CallLogCallerNumberType[]))] @@ -424,6 +427,9 @@ namespace ZoomNet.Json [JsonSerializable(typeof(ZoomNet.Models.PhoneCallRecordingTranscriptTimelineUser[]))] [JsonSerializable(typeof(ZoomNet.Models.PhoneCallRecordingType[]))] [JsonSerializable(typeof(ZoomNet.Models.PhoneCallUser[]))] + [JsonSerializable(typeof(ZoomNet.Models.PhoneCallUserProfile[]))] + [JsonSerializable(typeof(ZoomNet.Models.PhoneCallUserStatus[]))] + [JsonSerializable(typeof(ZoomNet.Models.PhoneCallPhoneNumber[]))] [JsonSerializable(typeof(ZoomNet.Models.PhoneNumber[]))] [JsonSerializable(typeof(ZoomNet.Models.PhoneType[]))] [JsonSerializable(typeof(ZoomNet.Models.PmiMeetingPasswordRequirementType[]))] diff --git a/Source/ZoomNet/Models/CallingPlan.cs b/Source/ZoomNet/Models/CallingPlan.cs new file mode 100644 index 00000000..4061e654 --- /dev/null +++ b/Source/ZoomNet/Models/CallingPlan.cs @@ -0,0 +1,34 @@ +using System.Text.Json.Serialization; + +namespace ZoomNet.Models; + +/// +/// Represents a calling plan. +/// +public class CallingPlan +{ + /// + /// Gets or sets the type of the calling plan. + /// + /// + /// The type of the calling plan. + /// + [JsonPropertyName("type")] + public CallingPlanType Type { get; set; } + + /// + /// Gets or sets the billing account ID. + /// + /// The billing account ID. + [JsonPropertyName("billing_account_id")] + public string BillingAccountId { get; set; } + + /// + /// Gets or sets the name of the billing account. + /// + /// + /// The name of the billing account. + /// + [JsonPropertyName("billing_account_name")] + public string BillingAccountName { get; set; } +} diff --git a/Source/ZoomNet/Models/CallingPlanType.cs b/Source/ZoomNet/Models/CallingPlanType.cs new file mode 100644 index 00000000..deabd1f7 --- /dev/null +++ b/Source/ZoomNet/Models/CallingPlanType.cs @@ -0,0 +1,387 @@ +namespace ZoomNet.Models; + +/// +/// Represents the type of calling plan. +/// +public enum CallingPlanType +{ + /// + /// No feature package. + /// + NoFeaturePackage = 1, + + /// + /// International toll number. + /// + InternationalTollNumber = 3, + + /// + /// International toll free number. + /// + InternationalTollFreeNumber = 4, + + /// + /// Bring your own carrier number. + /// + ByocNumber = 5, + + /// + /// BETA number. + /// + BetaNumber = 6, + + /// + /// Metered plan in California. + /// + MeteredPlanUsCa = 100, + + /// + /// Metered plan in Australia/New Zealand. + /// + MeteredPlanAuNz = 101, + + /// + /// Metered plan in Great Britian/Ireland. + /// + MeteredPlanGbIe = 102, + + /// + /// Metered EURA. + /// + MeteredEura = 103, + + /// + /// Metered EURB. + /// + MeteredEurb = 104, + + /// + /// Metered Japan. + /// + MeteredJp = 107, + + /// + /// Unlimited plan US California. + /// + UnlimitedPlanUsCa = 200, + + /// + /// Unlimited plan Australia/New Zealand. + /// + UnlimitedPlanAuNz = 201, + + /// + /// Unlimited plan Great Britain/Ireland. + /// + UnlimitedPlanGbIe = 202, + + /// + /// Unlimited EURA. + /// + UnlimitedEura = 203, + + /// + /// Unlimited EURB. + /// + UnlimitedEurb = 204, + + /// + /// Unlimited Japan. + /// + UnlimitedJp = 207, + + /// + /// US California number. + /// + UsCaNumber = 300, + + /// + /// Australia/New Zealand number. + /// + AuNzNumber = 301, + + /// + /// Great Britain/Ireland number. + /// + GbIeNumber = 302, + + /// + /// EURA number. + /// + EuraNumber = 303, + + /// + /// EURB number. + /// + EurbNumber = 304, + + /// + /// Japanese number. + /// + JpNumber = 307, + + /// + /// US California toll free number. + /// + UsCaTollfreeNumber = 400, + + /// + /// Australia toll free number. + /// + AuTollfreeNumber = 401, + + /// + /// Great Britain/Ireland toll free number. + /// + GbIeTollfreeNumber = 402, + + /// + /// New Zealand toll free number. + /// + NzTollfreeNumber = 403, + + /// + /// Global toll free number. + /// + GlobalTollfreeNumber = 404, + + /// + /// Beta. + /// + Beta = 600, + + /// + /// Unlimited domestic select. + /// + UnlimitedDomesticSelect = 1000, + + /// + /// Metered global select. + /// + MeteredGlobalSelect = 1001, + + /// + /// Unlimited domestic select number. + /// + UnlimitedDomesticSelectNumber = 2000, + + /// + /// Zoom Phone Pro. + /// + ZpPro = 3000, + + /// + /// Basic. + /// + Basic = 3010, + + /// + /// Zoom Phone common area. + /// + ZpCommonArea = 3040, + + /// + /// Reserved plan. + /// + ReservedPlan = 3098, + + /// + /// Basic migrated. + /// + BasicMigrated = 3099, + + /// + /// International select addon. + /// + InternationalSelectAddon = 4000, + + /// + /// Zoom Phone power pack. + /// + ZpPowerPack = 4010, + + /// + /// Premium member. + /// + PremiumNumber = 5000, + + /// + /// Metered US California number included. + /// + MeteredUsCaNumberIncluded = 30000, + + /// + /// Metered Australia/New Zealand number included. + /// + MeteredAuNzNumberIncluded = 30001, + + /// + /// Metered Great Britain/Ireland number included. + /// + MeteredGbIeNumberIncluded = 30002, + + /// + /// Metered EURA number included. + /// + MeteredEuraNumberIncluded = 30003, + + /// + /// Metered EURB number included. + /// + MeteredEurbNumberIncluded = 30004, + + /// + /// Metered Japan number included. + /// + MeteredJpNumberIncluded = 30007, + + /// + /// Unlimited Australia/New Zealand number included. + /// + UnlimitedAuNzNumberIncluded = 31001, + + /// + /// Unlimited Great Britain/Ireland number included. + /// + UnlimitedGbIeNumberIncluded = 31002, + + /// + /// Unlimited EURA number included. + /// + UnlimitedEuraNumberIncluded = 31003, + + /// + /// Unlimited EURB number included. + /// + UnlimitedEurbNumberIncluded = 31004, + + /// + /// Unlimited Japan number included. + /// + UnlimitedJpNumberIncluded = 31007, + + /// + /// Unlimited domestic select number included. + /// + UnlimitedDomesticSelectNumberIncluded = 31005, + + /// + /// Metered global select number included. + /// + MeteredGlobalSelectNumberIncluded = 31006, + + /// + /// Meetings pro unlimited US California. + /// + MeetingsProUnlimitedUsCa = 40200, + + /// + /// Meetings pro unlimited Australia/New Zealand. + /// + MeetingsProUnlimitedAuNz = 40201, + + /// + /// Meetings pro unlimited Great Britain/Ireland. + /// + MeetingsProUnlimitedGbIe = 40202, + + /// + /// Meetings pro unlimited Japan. + /// + MeetingsProUnlimitedJp = 40207, + + /// + /// Meetings pro global select. + /// + MeetingsProGlobalSelect = 41000, + + /// + /// Meetings pro PN Pro. + /// + MeetingsProPnPro = 43000, + + /// + /// Meetings business unlimited US California. + /// + MeetingsBusUnlimitedUsCa = 50200, + + /// + /// Meetings business unlimited Australia/New Zealand. + /// + MeetingsBusUnlimitedAuNz = 50201, + + /// + /// Meetings business unlimited Great Britain/Ireland. + /// + MeetingsBusUnlimitedGbIe = 50202, + + /// + /// Meetings business unlimited Japan. + /// + MeetingsBusUnlimitedJp = 50207, + + /// + /// Meetings business global select. + /// + MeetingsBusGlobalSelect = 51000, + + /// + /// Meetings business PN Pro. + /// + MeetingsBusPnPro = 53000, + + /// + /// Meetings enterprise unlimited US California. + /// + MeetingsEntUnlimitedUsCa = 60200, + + /// + /// Meetings enterprise unlimited Australia/New Zealand. + /// + MeetingsEntUnlimitedAuNz = 60201, + + /// + /// Meetings enterprise unlimited Great Britain/Ireland. + /// + MeetingsEntUnlimitedGbIe = 60202, + + /// + /// Meetings enterprise unlimited Japan. + /// + MeetingsEntUnlimitedJp = 60207, + + /// + /// Meetings enterprise global select. + /// + MeetingsEntGlobalSelect = 61000, + + /// + /// Meetings enterprise PN Pro. + /// + MeetingsEntPnPro = 63000, + + /// + /// Meetings US California number included. + /// + MeetingsUsCaNumberIncluded = 70200, + + /// + /// Meetings Australia/New Zealand number included. + /// + MeetingsAuNzNumberIncluded = 70201, + + /// + /// Meetings Great Britain/Ireland number included. + /// + MeetingsGbIeNumberIncluded = 70202, + + /// + /// Meetings Japanese number included. + /// + MeetingsJpNumberIncluded = 70207, + + /// + /// Meetings global select number included. + /// + MeetingsGlobalSelectNumberIncluded = 71000 +} diff --git a/Source/ZoomNet/Models/EmergencyAddress.cs b/Source/ZoomNet/Models/EmergencyAddress.cs new file mode 100644 index 00000000..0c14a1fe --- /dev/null +++ b/Source/ZoomNet/Models/EmergencyAddress.cs @@ -0,0 +1,51 @@ +using System.Text.Json.Serialization; + +namespace ZoomNet.Models; + +/// +/// Represents an emergency address. +/// +public class EmergencyAddress +{ + /// + /// Gets or sets the first line of the address. + /// + [JsonPropertyName("address_line1")] + public string AddressLine1 { get; set; } + + /// + /// Gets or sets the second line of the address. + /// + [JsonPropertyName("address_line2")] + public string AddressLine2 { get; set; } + + /// + /// Gets or sets the city. + /// + [JsonPropertyName("city")] + public string City { get; set; } + + /// + /// Gets or sets the country. + /// + [JsonPropertyName("country")] + public string Country { get; set; } + + /// + /// Gets or sets the emergency address id. + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// Gets or sets the state code. + /// + [JsonPropertyName("state_code")] + public string StateCode { get; set; } + + /// + /// Gets or sets the postal code. + /// + [JsonPropertyName("zip")] + public string Zip { get; set; } +} diff --git a/Source/ZoomNet/Models/PhoneCallPhoneNumber.cs b/Source/ZoomNet/Models/PhoneCallPhoneNumber.cs new file mode 100644 index 00000000..ad76accd --- /dev/null +++ b/Source/ZoomNet/Models/PhoneCallPhoneNumber.cs @@ -0,0 +1,27 @@ +using System.Text.Json.Serialization; + +namespace ZoomNet.Models; + +/// +/// Represents a phone number used in a phone call. +/// +public class PhoneCallPhoneNumber +{ + /// + /// Gets or sets the phone number ID. + /// + /// + /// The phone number ID. + /// + [JsonPropertyName("id")] + public string PhoneNumberId { get; set; } + + /// + /// Gets or sets the phone number. + /// + /// + /// The phone number. + /// + [JsonPropertyName("number")] + public string PhoneNumber { get; set; } +} diff --git a/Source/ZoomNet/Models/PhoneCallUserProfile.cs b/Source/ZoomNet/Models/PhoneCallUserProfile.cs new file mode 100644 index 00000000..de9ffd70 --- /dev/null +++ b/Source/ZoomNet/Models/PhoneCallUserProfile.cs @@ -0,0 +1,87 @@ +using System.Text.Json.Serialization; + +namespace ZoomNet.Models; + +/// +/// Phone call user profile information. +/// +public class PhoneCallUserProfile +{ + /// + /// Gets or sets the calling plans. + /// + [JsonPropertyName("calling_plans")] + public CallingPlan[] CallingPlans { get; set; } + + /// + /// Gets or sets the cost center. + /// + [JsonPropertyName("cost_center")] + public string CostCenter { get; set; } + + /// + /// Gets or sets the department of the object. + /// + [JsonPropertyName("department")] + public string Department { get; set; } + + /// + /// Gets or sets the email address. + /// + [JsonPropertyName("email")] + public string Email { get; set; } + + /// + /// Gets or sets the emergency address. + /// + [JsonPropertyName("emergency_address")] + public EmergencyAddress EmergencyAddress { get; set; } + + /// + /// Gets or sets the extension ID. + /// + [JsonPropertyName("extension_id")] + public string ExtensionId { get; set; } + + /// + /// Gets or sets the extension number. + /// + [JsonPropertyName("extension_number")] + public int ExtensionNumber { get; set; } + + /// + /// Gets or sets the Zoom user ID. + /// + [JsonPropertyName("id")] + public string Id { get; set; } + + /// + /// Gets or sets the phone numbers. + /// + [JsonPropertyName("phone_numbers")] + public PhoneCallPhoneNumber[] PhoneNumbers { get; set; } + + /// + /// Gets or sets the Zoom phone user id. + /// + [JsonPropertyName("phone_user_id")] + public string PhoneUserId { get; set; } + + /// + /// Gets or sets a value indicating whether the user is a site admin. + /// + [JsonPropertyName("site_admin")] + public bool SiteAdmin { get; set; } + + /// + /// Gets or sets the site id. + /// + [JsonPropertyName("site_id")] + public string SiteId { get; set; } + + /// + /// Gets or sets the status of the user. + /// + [JsonPropertyName("status")] + public PhoneCallUserStatus Status { get; set; } +} diff --git a/Source/ZoomNet/Models/PhoneCallUserStatus.cs b/Source/ZoomNet/Models/PhoneCallUserStatus.cs new file mode 100644 index 00000000..a5b09771 --- /dev/null +++ b/Source/ZoomNet/Models/PhoneCallUserStatus.cs @@ -0,0 +1,21 @@ +using System.Runtime.Serialization; + +namespace ZoomNet.Models; + +/// +/// Represents the status of a phone user. +/// +public enum PhoneCallUserStatus +{ + /// + /// An active user. + /// + [EnumMember(Value = "activate")] + Active, + + /// + /// User has been deactivated from the Zoom Phone system. + /// + [EnumMember(Value = "deactivate")] + Inactive +} diff --git a/Source/ZoomNet/Resources/IPhone.cs b/Source/ZoomNet/Resources/IPhone.cs index db218fec..fac8a3f8 100644 --- a/Source/ZoomNet/Resources/IPhone.cs +++ b/Source/ZoomNet/Resources/IPhone.cs @@ -46,5 +46,18 @@ Task GetRecordingTranscriptAsync( string recordingId, CancellationToken cancellationToken = default); #endregion + + #region Users Endpoints + + /// + /// Retrieves the phone call user profile for the specified user ID asynchronously. + /// + /// The ID of the user for which to retrieve the phone call user profile. + /// A cancellation token that can be used to cancel the asynchronous operation. + /// A task representing the asynchronous operation. The task result contains the phone call user profile. + Task GetPhoneCallUserProfileAsync( + string userId, CancellationToken cancellationToken = default); + + #endregion } } diff --git a/Source/ZoomNet/Resources/Phone.cs b/Source/ZoomNet/Resources/Phone.cs index e81e7580..fa9e3ea8 100644 --- a/Source/ZoomNet/Resources/Phone.cs +++ b/Source/ZoomNet/Resources/Phone.cs @@ -50,5 +50,18 @@ public Task GetRecordingTranscriptAsync( } #endregion + + #region Users Endpoints + + /// + public Task GetPhoneCallUserProfileAsync(string userId, CancellationToken cancellationToken = default) + { + return _client + .GetAsync($"phone/users/{userId}") + .WithCancellationToken(cancellationToken) + .AsObject(); + } + + #endregion } } From d4493b89c5a6529d7a823e224606ecead045db38 Mon Sep 17 00:00:00 2001 From: jericho Date: Sat, 20 Jan 2024 10:31:00 -0500 Subject: [PATCH 4/5] Upgrade nuget packages --- Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj | 4 ++-- Source/ZoomNet/ZoomNet.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj b/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj index 26f5e505..1f1dee94 100644 --- a/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj +++ b/Source/ZoomNet.UnitTests/ZoomNet.UnitTests.csproj @@ -20,8 +20,8 @@ - - + + all runtime; build; native; contentfiles; analyzers diff --git a/Source/ZoomNet/ZoomNet.csproj b/Source/ZoomNet/ZoomNet.csproj index b6510dce..076cda39 100644 --- a/Source/ZoomNet/ZoomNet.csproj +++ b/Source/ZoomNet/ZoomNet.csproj @@ -36,7 +36,7 @@ - + From ab203f275ff0079ad8244152dbdd3a4dc38b81e2 Mon Sep 17 00:00:00 2001 From: jericho Date: Sat, 20 Jan 2024 10:32:44 -0500 Subject: [PATCH 5/5] Refresh resource files --- build.cake | 6 +++++- global.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/build.cake b/build.cake index b083390c..746a88a3 100644 --- a/build.cake +++ b/build.cake @@ -3,7 +3,7 @@ #tool dotnet:?package=coveralls.net&version=4.0.1 #tool nuget:https://f.feedz.io/jericho/jericho/nuget/?package=GitReleaseManager&version=0.17.0-collaborators0003 #tool nuget:?package=ReportGenerator&version=5.2.0 -#tool nuget:?package=xunit.runner.console&version=2.6.3 +#tool nuget:?package=xunit.runner.console&version=2.6.6 #tool nuget:?package=CodecovUploader&version=0.7.1 // Install addins. @@ -308,6 +308,8 @@ Task("Upload-Coverage-Result-Coveralls") .WithCriteria(() => isMainRepo) .Does(() => { + if(string.IsNullOrEmpty(coverallsToken)) throw new InvalidOperationException("Could not resolve Coveralls token."); + CoverallsNet(new FilePath(coverageFile), CoverallsNetReportType.OpenCover, new CoverallsNetSettings() { RepoToken = coverallsToken, @@ -328,6 +330,8 @@ Task("Upload-Coverage-Result-Codecov") .WithCriteria(() => isMainRepo) .Does(() => { + if(string.IsNullOrEmpty(codecovToken)) throw new InvalidOperationException("Could not resolve CodeCov token."); + Codecov(new CodecovSettings { Files = new[] { coverageFile }, diff --git a/global.json b/global.json index 8e621cac..f43378f6 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "8.0.100", + "version": "8.0.101", "rollForward": "patch", "allowPrerelease": false }