From c348d2c22bfa7499d40b13a0ae29091a1d0e2060 Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Tue, 8 Oct 2024 18:00:09 +0100 Subject: [PATCH 1/8] Support availability rule APIs --- src/Cronofy/AvailabilityRule.cs | 181 ++++++++++++++++++ src/Cronofy/CronofyAccountClient.cs | 61 ++++++ src/Cronofy/ICronofyAccountClient.cs | 55 +++++- .../Requests/UpsertAvailabilityRuleRequest.cs | 82 ++++++++ .../Responses/AvailabilityRuleResponse.cs | 115 +++++++++++ .../ListAvailabilityRulesResponse.cs | 21 ++ src/Cronofy/UrlProvider.cs | 174 +++++------------ .../DeleteAvailabilityRule.cs | 21 ++ .../GetAvailabilityRule.cs | 78 ++++++++ .../ListAvailabilityRules.cs | 127 ++++++++++++ .../UpsertAvailabilityRule.cs | 127 ++++++++++++ 11 files changed, 916 insertions(+), 126 deletions(-) create mode 100644 src/Cronofy/AvailabilityRule.cs create mode 100644 src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs create mode 100644 src/Cronofy/Responses/AvailabilityRuleResponse.cs create mode 100644 src/Cronofy/Responses/ListAvailabilityRulesResponse.cs create mode 100644 test/Cronofy.Test/CronofyAccountClientTests/DeleteAvailabilityRule.cs create mode 100644 test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs create mode 100644 test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs create mode 100644 test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs diff --git a/src/Cronofy/AvailabilityRule.cs b/src/Cronofy/AvailabilityRule.cs new file mode 100644 index 0000000..c63039e --- /dev/null +++ b/src/Cronofy/AvailabilityRule.cs @@ -0,0 +1,181 @@ +namespace Cronofy +{ + using System; + using System.Linq; + + /// + /// Class for representing an availability rule. + /// + public sealed class AvailabilityRule + { + /// + /// Gets or sets the unique identifier of the availability rule. + /// + /// + /// The unique identifier of the availability rule. + /// + public string AvailabilityRuleId { get; set; } + + /// + /// Gets or sets the time zone for which the availability rule start and end times are represented in. + /// + /// + /// The time zone for which the availability rule start and end times are represented in. + /// + public string TimeZoneId { get; set; } + + /// + /// Gets or sets the calendars that should impact the user's availability. + /// + /// + /// The calendars that should impact the user's availability. + /// + public string[] CalendarIds { get; set; } + + /// + /// Gets or sets the weekly recurring periods for the availability rule. + /// + /// + /// The weekly recurring periods for the availability rule. + /// + public WeeklyPeriod[] WeeklyPeriods { get; set; } + + /// + public override int GetHashCode() + { + return this.AvailabilityRuleId.GetHashCode(); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + return obj is AvailabilityRule && this.Equals((AvailabilityRule)obj); + } + + /// + /// Determines whether the specified + /// is equal to the current . + /// + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is + /// equal to the current ; otherwise, + /// false. + /// + public bool Equals(AvailabilityRule other) + { + return this.AvailabilityRuleId == other.AvailabilityRuleId && + this.TimeZoneId == other.TimeZoneId && + this.CalendarIds.SequenceEqual(other.CalendarIds) && + this.WeeklyPeriods.SequenceEqual(other.WeeklyPeriods); + } + + /// + public override string ToString() + { + return string.Format( + "<{0} AvailabilityRuleId={1}, TimeZoneId={2}, CalendarIds={3}, WeeklyPeriods={4}>", + this.GetType(), + this.AvailabilityRuleId, + this.TimeZoneId, + this.CalendarIds, + this.WeeklyPeriods); + } + + /// + /// Class to represent a weekly period. + /// + public class WeeklyPeriod + { + /// + /// Gets or sets the week day the period applies to. + /// + /// + /// The week day the period applies to. + /// + public string Day { get; set; } + + /// + /// Gets or sets the time of day the period should start. + /// + /// + /// The time of day the period should start. + /// + public string StartTime { get; set; } + + /// + /// Gets or sets the time of day the period should end. + /// + /// + /// The time of day the period should end. + /// + public string EndTime { get; set; } + + /// + public override int GetHashCode() + { + return this.Day.GetHashCode() ^ this.StartTime.GetHashCode() ^ this.EndTime.GetHashCode(); + } + + /// + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + return obj is WeeklyPeriod && this.Equals((WeeklyPeriod)obj); + } + + /// + /// Determines whether the specified + /// is equal to the current . + /// + /// + /// The to compare with the current + /// . + /// + /// + /// true if the specified is + /// equal to the current ; otherwise, + /// false. + /// + public bool Equals(WeeklyPeriod other) + { + return this.Day == other.Day && + this.StartTime == other.StartTime && + this.EndTime == other.EndTime; + } + + /// + public override string ToString() + { + return string.Format( + "<{0} Day={1}, StartTime={2}, EndTime={3}>", + this.GetType(), + this.Day, + this.StartTime, + this.EndTime); + } + } + } +} diff --git a/src/Cronofy/CronofyAccountClient.cs b/src/Cronofy/CronofyAccountClient.cs index d5fe8e6..e9bd39e 100644 --- a/src/Cronofy/CronofyAccountClient.cs +++ b/src/Cronofy/CronofyAccountClient.cs @@ -560,6 +560,67 @@ public string GetConferencingServiceAuthorizationUrl(ConferencingServiceAuthoriz return response.AuthorizationRequest.Url; } + /// + public AvailabilityRule GetAvailabilityRule(string availabilityRuleId) + { + Preconditions.NotEmpty("availabilityRuleId", availabilityRuleId); + + var request = new HttpRequest(); + + request.Method = "GET"; + request.Url = string.Format(this.UrlProvider.AvailabilityRuleUrl, availabilityRuleId); + request.AddOAuthAuthorization(this.AccessToken); + + var response = this.HttpClient.GetJsonResponse(request); + + return response.ToAvailabilityRule(); + } + + /// + public IEnumerable GetAvailabilityRules() + { + var request = new HttpRequest(); + + request.Method = "GET"; + request.Url = this.UrlProvider.AvailabilityRulesUrl; + request.AddOAuthAuthorization(this.AccessToken); + + var response = this.HttpClient.GetJsonResponse(request); + + return response.AvailabilityRules.Select(ap => ap.ToAvailabilityRule()); + } + + /// + public AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest upsertAvailabilityRuleRequest) + { + Preconditions.NotNull("upsertAvailabilityRuleRequest", upsertAvailabilityRuleRequest); + + var request = new HttpRequest(); + + request.Method = "POST"; + request.Url = this.UrlProvider.AvailabilityRulesUrl; + request.AddOAuthAuthorization(this.AccessToken); + request.SetJsonBody(upsertAvailabilityRuleRequest); + + var response = this.HttpClient.GetJsonResponse(request); + + return response.ToAvailabilityRule(); + } + + /// + public void DeleteAvailabilityRule(string availabilityRuleId) + { + Preconditions.NotEmpty("availabilityRuleId", availabilityRuleId); + + var request = new HttpRequest(); + + request.Method = "DELETE"; + request.Url = string.Format(this.UrlProvider.AvailabilityRuleUrl, availabilityRuleId); + request.AddOAuthAuthorization(this.AccessToken); + + this.HttpClient.GetValidResponse(request); + } + /// /// Creates a calendar. /// diff --git a/src/Cronofy/ICronofyAccountClient.cs b/src/Cronofy/ICronofyAccountClient.cs index 4bfdfdb..f94a9ca 100644 --- a/src/Cronofy/ICronofyAccountClient.cs +++ b/src/Cronofy/ICronofyAccountClient.cs @@ -554,11 +554,64 @@ public interface ICronofyAccountClient : ICronofyUserInfoClient /// /// The URL which the end-user should visit. /// - /// Thrown if if null, or it doesn't contain a Redirect URI. + /// Thrown if is null, or it doesn't contain a Redirect URI. /// /// /// Thrown if an error is encountered whilst making the request. /// string GetConferencingServiceAuthorizationUrl(ConferencingServiceAuthorizationRequest conferencingServiceAuthorizationRequest); + + /// + /// Reads a single availability rule. + /// + /// + /// The unique identifier of the availability rule. + /// + /// The availability rule. + /// + /// Thrown if is null, or empty. + /// + /// + /// Thrown if an error is encountered whilst making the request. + /// + AvailabilityRule GetAvailabilityRule(string availabilityRuleId); + + /// + /// Retrieves all availability rules saved against an account. + /// + /// The list of all availability rules. + /// + /// Thrown if an error is encountered whilst making the request. + /// + IEnumerable GetAvailabilityRules(); + + /// + /// Creates or updates an availability rule. + /// + /// + /// The parameters for the request, must not be null. + /// + /// The created or updated availability rule. + /// + /// Thrown if is null. + /// + /// + /// Thrown if an error is encountered whilst making the request. + /// + AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest upsertAvailabilityRuleRequest); + + /// + /// Deletes an availability rule for the authenticated account. + /// + /// + /// The unique identifier of the availability rule. + /// + /// + /// Thrown if is null, or empty. + /// + /// + /// Thrown if an error is encountered whilst making the request. + /// + void DeleteAvailabilityRule(string availabilityRuleId); } } diff --git a/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs new file mode 100644 index 0000000..ca35ed1 --- /dev/null +++ b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs @@ -0,0 +1,82 @@ +namespace Cronofy.Requests +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Class for the serialization of an upsert availability rule request. + /// + public sealed class UpsertAvailabilityRuleRequest + { + /// + /// Gets or sets the unique identifier of the availability rule. + /// + /// + /// The unique identifier of the availability rule. + /// + [JsonProperty("availability_rule_id")] + public string AvailabilityRuleId { get; set; } + + /// + /// Gets or sets the time zone for which the availability rule start and end times are represented in. + /// + /// + /// The time zone for which the availability rule start and end times are represented in. + /// + [JsonProperty("tzid")] + public string TimeZoneId { get; set; } + + /// + /// Gets or sets the calendars that should impact the user's availability. + /// + /// + /// The calendars that should impact the user's availability. + /// + [JsonProperty("calendar_ids")] + public IEnumerable CalendarIds { get; set; } + + /// + /// Gets or sets the weekly recurring periods for the availability rule. + /// + /// + /// The weekly recurring periods for the availability rule. + /// + [JsonProperty("weekly_periods")] + public IEnumerable WeeklyPeriods { get; set; } + + /// + /// Class for the serialization of a weekly period within an availability rule. + /// + public sealed class WeeklyPeriod + { + /// + /// Gets or sets the week day the period applies to. + /// + /// + /// The week day the period applies to. + /// + [JsonProperty("day")] + public string Day { get; set; } + + /// + /// Gets or sets the time of day the period should start. + /// + /// + /// The time of day the period should start. + /// + [JsonProperty("start_time")] + public string StartTime { get; set; } + + /// + /// Gets or sets the time of day the period should end. + /// + /// + /// The time of day the period should end. + /// + [JsonProperty("end_time")] + public string EndTime { get; set; } + } + } +} diff --git a/src/Cronofy/Responses/AvailabilityRuleResponse.cs b/src/Cronofy/Responses/AvailabilityRuleResponse.cs new file mode 100644 index 0000000..5d16643 --- /dev/null +++ b/src/Cronofy/Responses/AvailabilityRuleResponse.cs @@ -0,0 +1,115 @@ +namespace Cronofy.Responses +{ + using System; + using System.Collections.Generic; + using System.Linq; + using Newtonsoft.Json; + + /// + /// Class for the deserialization of a read availability rule response. + /// + internal sealed class AvailabilityRuleResponse + { + /// + /// Gets or sets the unique identifier of the availability rule. + /// + /// + /// The unique identifier of the availability rule. + /// + [JsonProperty("availability_rule_id")] + public string AvailabilityRuleId { get; set; } + + /// + /// Gets or sets the time zone for which the availability rule start and end times are represented in. + /// + /// + /// The time zone for which the availability rule start and end times are represented in. + /// + [JsonProperty("tzid")] + public string TimeZoneId { get; set; } + + /// + /// Gets or sets the calendars that should impact the user's availability. + /// + /// + /// The calendars that should impact the user's availability. + /// + [JsonProperty("calendar_ids")] + public IEnumerable CalendarIds { get; set; } + + /// + /// Gets or sets the weekly recurring periods for the availability rule. + /// + /// + /// The weekly recurring periods for the availability rule. + /// + [JsonProperty("weekly_periods")] + public IEnumerable WeeklyPeriods { get; set; } + + /// + /// Converts the response to an . + /// + /// + /// An . + /// + public AvailabilityRule ToAvailabilityRule() + { + return new AvailabilityRule + { + AvailabilityRuleId = this.AvailabilityRuleId, + TimeZoneId = this.TimeZoneId, + CalendarIds = this.CalendarIds.ToArray(), + WeeklyPeriods = this.WeeklyPeriods.Select(weeklyPeriod => weeklyPeriod.ToWeeklyPeriod()).ToArray(), + }; + } + + /// + /// Class for the deserialization of a weekly period within an availability rule. + /// + internal sealed class WeeklyPeriod + { + /// + /// Gets or sets the week day the period applies to. + /// + /// + /// The week day the period applies to. + /// + [JsonProperty("day")] + public string Day { get; set; } + + /// + /// Gets or sets the time of day the period should start. + /// + /// + /// The time of day the period should start. + /// + [JsonProperty("start_time")] + public string StartTime { get; set; } + + /// + /// Gets or sets the time of day the period should end. + /// + /// + /// The time of day the period should end. + /// + [JsonProperty("end_time")] + public string EndTime { get; set; } + + /// + /// Converts the response to an . + /// + /// + /// An . + /// + public AvailabilityRule.WeeklyPeriod ToWeeklyPeriod() + { + return new AvailabilityRule.WeeklyPeriod + { + Day = this.Day, + StartTime = this.StartTime, + EndTime = this.EndTime, + }; + } + } + } +} diff --git a/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs b/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs new file mode 100644 index 0000000..566ff26 --- /dev/null +++ b/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs @@ -0,0 +1,21 @@ +namespace Cronofy.Responses +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// Class for the deserialization of a list availability rules response. + /// + internal sealed class ListAvailabilityRulesResponse + { + /// + /// Gets or sets the weekly recurring periods for the availability rule. + /// + /// + /// The weekly recurring periods for the availability rule. + /// + [JsonProperty("availability_rules")] + public IEnumerable AvailabilityRules { get; set; } + } +} diff --git a/src/Cronofy/UrlProvider.cs b/src/Cronofy/UrlProvider.cs index 130dbbb..d8f2d48 100644 --- a/src/Cronofy/UrlProvider.cs +++ b/src/Cronofy/UrlProvider.cs @@ -175,6 +175,16 @@ public sealed class UrlProvider /// private const string AttachmentsUrlFormat = "https://api{0}.cronofy.com/v1/attachments"; + /// + /// The URL of the Availability Rule endpoint. + /// + private const string AvailabilityRulesUrlFormat = "https://api{0}.cronofy.com/v1/availability_rules"; + + /// + /// The URL of the Availability Rule endpoint for a specific rule. + /// + private const string AvailabilityRuleUrlFormat = "https://api{0}.cronofy.com/v1/availability_rules/{{0}}"; + /// /// Initializes a new instance of the class. /// @@ -224,6 +234,8 @@ internal UrlProvider(string dataCenter) this.ElementTokensUrl = string.Format(ElementTokensUrlFormat, suffix); this.ConferencingServiceAuthorizationUrl = string.Format(ConferencingServiceAuthorizationUrlFormat, suffix); this.AttachmentsUrl = string.Format(AttachmentsUrlFormat, suffix); + this.AvailabilityRulesUrl = string.Format(AvailabilityRulesUrlFormat, suffix); + this.AvailabilityRuleUrl = string.Format(AvailabilityRuleUrlFormat, suffix); } /// @@ -232,11 +244,7 @@ internal UrlProvider(string dataCenter) /// /// The authorization URL. /// - public string AuthorizationUrl - { - get; - private set; - } + public string AuthorizationUrl { get; private set; } /// /// Gets the Enterprise Connect authorization URL. @@ -244,11 +252,7 @@ public string AuthorizationUrl /// /// The Enterprise Connect authorization URL. /// - public string EnterpriseConnectAuthorizationUrl - { - get; - private set; - } + public string EnterpriseConnectAuthorizationUrl { get; private set; } /// /// Gets the OAuth token URL. @@ -256,11 +260,7 @@ public string EnterpriseConnectAuthorizationUrl /// /// The OAuth token URL. /// - public string TokenUrl - { - get; - private set; - } + public string TokenUrl { get; private set; } /// /// Gets the OAuth token revocation URL. @@ -268,11 +268,7 @@ public string TokenUrl /// /// The OAuth token revocation URL. /// - public string TokenRevocationUrl - { - get; - private set; - } + public string TokenRevocationUrl { get; private set; } /// /// Gets the userinfo URL. @@ -280,11 +276,7 @@ public string TokenRevocationUrl /// /// The userinfo URL. /// - public string UserInfoUrl - { - get; - private set; - } + public string UserInfoUrl { get; private set; } /// /// Gets the resources URL. @@ -292,11 +284,7 @@ public string UserInfoUrl /// /// The resources URL. /// - public string ResourcesUrl - { - get; - private set; - } + public string ResourcesUrl { get; private set; } /// /// Gets the authorize with service account URL. @@ -304,11 +292,7 @@ public string ResourcesUrl /// /// The authorize with service account URL. /// - public string AuthorizeWithServiceAccountUrl - { - get; - private set; - } + public string AuthorizeWithServiceAccountUrl { get; private set; } /// /// Gets the account URL. @@ -316,11 +300,7 @@ public string AuthorizeWithServiceAccountUrl /// /// The account URL. /// - public string AccountUrl - { - get; - private set; - } + public string AccountUrl { get; private set; } /// /// Gets the profiles URL. @@ -328,11 +308,7 @@ public string AccountUrl /// /// The profiles URL. /// - public string ProfilesUrl - { - get; - private set; - } + public string ProfilesUrl { get; private set; } /// /// Gets the calendars URL. @@ -340,11 +316,7 @@ public string ProfilesUrl /// /// The calendars URL. /// - public string CalendarsUrl - { - get; - private set; - } + public string CalendarsUrl { get; private set; } /// /// Gets the free busy URL. @@ -352,11 +324,7 @@ public string CalendarsUrl /// /// The free busy URL. /// - public string FreeBusyUrl - { - get; - private set; - } + public string FreeBusyUrl { get; private set; } /// /// Gets the events URL. @@ -364,11 +332,7 @@ public string FreeBusyUrl /// /// The events URL. /// - public string EventsUrl - { - get; - private set; - } + public string EventsUrl { get; private set; } /// /// Gets the managed event URL format. @@ -376,11 +340,7 @@ public string EventsUrl /// /// The managed event URL format. /// - public string ManagedEventUrlFormat - { - get; - private set; - } + public string ManagedEventUrlFormat { get; private set; } /// /// Gets the participation status URL format. @@ -388,11 +348,7 @@ public string ManagedEventUrlFormat /// /// The participation status URL format. /// - public string ParticipationStatusUrlFormat - { - get; - private set; - } + public string ParticipationStatusUrlFormat { get; private set; } /// /// Gets the channels URL. @@ -400,11 +356,7 @@ public string ParticipationStatusUrlFormat /// /// The channels URL. /// - public string ChannelsUrl - { - get; - private set; - } + public string ChannelsUrl { get; private set; } /// /// Gets the channel URL format. @@ -412,11 +364,7 @@ public string ChannelsUrl /// /// The channel URL format. /// - public string ChannelUrlFormat - { - get; - private set; - } + public string ChannelUrlFormat { get; private set; } /// /// Gets the permissions URL. @@ -424,11 +372,7 @@ public string ChannelUrlFormat /// /// The permissions URL. /// - public string PermissionsUrl - { - get; - private set; - } + public string PermissionsUrl { get; private set; } /// /// Gets the availability URL. @@ -436,11 +380,7 @@ public string PermissionsUrl /// /// The availability URL. /// - public string AvailabilityUrl - { - get; - private set; - } + public string AvailabilityUrl { get; private set; } /// /// Gets the add to calendar URL. @@ -448,11 +388,7 @@ public string AvailabilityUrl /// /// The add to calendar URL. /// - public string AddToCalendarUrl - { - get; - private set; - } + public string AddToCalendarUrl { get; private set; } /// /// Gets the real time scheduling URL. @@ -460,11 +396,7 @@ public string AddToCalendarUrl /// /// The real time scheduling URL. /// - public string RealTimeSchedulingUrl - { - get; - private set; - } + public string RealTimeSchedulingUrl { get; private set; } /// /// Gets the real time scheduling by ID URL. @@ -472,11 +404,7 @@ public string RealTimeSchedulingUrl /// /// The real time scheduling by ID URL. /// - public string RealTimeSchedulingByIdUrl - { - get; - private set; - } + public string RealTimeSchedulingByIdUrl { get; private set; } /// /// Gets the real time scheduling disable URL format. @@ -484,11 +412,7 @@ public string RealTimeSchedulingByIdUrl /// /// The real time scheduling disable URL format. /// - public string DisableRealTimeSchedulingUrlFormat - { - get; - private set; - } + public string DisableRealTimeSchedulingUrlFormat { get; private set; } /// /// Gets the link tokens URL. @@ -496,11 +420,7 @@ public string DisableRealTimeSchedulingUrlFormat /// /// The link tokens URL. /// - public string LinkTokensUrl - { - get; - private set; - } + public string LinkTokensUrl { get; private set; } /// /// Gets the revoke profile authorization URL format. @@ -508,11 +428,7 @@ public string LinkTokensUrl /// /// The revoke profile authorization URL format. /// - public string RevokeProfileAuthorizationUrlFormat - { - get; - private set; - } + public string RevokeProfileAuthorizationUrlFormat { get; private set; } /// /// Gets the Smart Invite URL. @@ -526,11 +442,7 @@ public string RevokeProfileAuthorizationUrlFormat /// /// The batch request URL. /// - public string BatchUrl - { - get; - private set; - } + public string BatchUrl { get; private set; } /// /// Gets the application calendars URL. @@ -579,5 +491,17 @@ public string BatchUrl /// /// The attachments URL. public string AttachmentsUrl { get; private set; } + + /// + /// Gets the Availability Rule URL. + /// + /// The Availability Rule URL. + public string AvailabilityRulesUrl { get; private set; } + + /// + /// Gets the Availability Rule URL for a specific rule. + /// + /// The Availability Rule URL for a specific rule. + public string AvailabilityRuleUrl { get; private set; } } } diff --git a/test/Cronofy.Test/CronofyAccountClientTests/DeleteAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/DeleteAvailabilityRule.cs new file mode 100644 index 0000000..efdc012 --- /dev/null +++ b/test/Cronofy.Test/CronofyAccountClientTests/DeleteAvailabilityRule.cs @@ -0,0 +1,21 @@ +namespace Cronofy.Test.CronofyAccountClientTests +{ + using NUnit.Framework; + + internal sealed class DeleteAvailabilityRule : Base + { + private const string AvailabilityRuleId = "my_really_cool_rule_id"; + + [Test] + public void CanDeleteAvailabilityRule() + { + this.Http.Stub( + HttpDelete + .Url("https://api.cronofy.com/v1/availability_rules/" + AvailabilityRuleId) + .RequestHeader("Authorization", "Bearer " + AccessToken) + .ResponseCode(202)); + + this.Client.DeleteAvailabilityRule(AvailabilityRuleId); + } + } +} diff --git a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs new file mode 100644 index 0000000..0685045 --- /dev/null +++ b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs @@ -0,0 +1,78 @@ +namespace Cronofy.Test.CronofyAccountClientTests +{ + using NUnit.Framework; + + internal sealed class GetAvailabilityRule : Base + { + private const string AvailabilityRuleId = "my_really_cool_rule_id"; + + [Test] + public void CanGetAvailabilityRule() + { + this.Http.Stub( + HttpGet + .Url("https://api.cronofy.com/v1/availability_rules/" + AvailabilityRuleId) + .RequestHeader("Authorization", "Bearer " + AccessToken) + .ResponseCode(200) + .ResponseBodyFormat( + @" + {{ + ""availability_rule_id"": ""{0}"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + {{ + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }}, + {{ + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }}, + {{ + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }} + ] + }} + ", AvailabilityRuleId)); + + var actualResponse = this.Client.GetAvailabilityRule(AvailabilityRuleId); + + var expectedResponse = new AvailabilityRule + { + AvailabilityRuleId = AvailabilityRuleId, + TimeZoneId = "America/Chicago", + CalendarIds = new[] { "cal_n23kjnwrw2_jsdfjksn234" }, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "09:30", + EndTime = "12:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "14:00", + EndTime = "17:00", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "wednesday", + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }; + + Assert.AreEqual(expectedResponse, actualResponse); + } + } +} diff --git a/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs new file mode 100644 index 0000000..6d64214 --- /dev/null +++ b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs @@ -0,0 +1,127 @@ +namespace Cronofy.Test.CronofyAccountClientTests +{ + using NUnit.Framework; + + internal sealed class ListAvailabilityRules : Base + { + [Test] + public void CanListAvailabilityRules() + { + this.Http.Stub( + HttpGet + .Url("https://api.cronofy.com/v1/availability_rules") + .RequestHeader("Authorization", "Bearer " + AccessToken) + .ResponseCode(200) + .ResponseBody(@" + { + ""availability_rules"": [ + { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + }, + { + ""availability_rule_id"": ""another_rule"", + ""tzid"": ""Europe/London"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"", + ""cal_n23kjnwrw2_th53tksn567"", + ], + ""weekly_periods"": [ + { + ""day"": ""saturday"", + ""start_time"": ""09:00"", + ""end_time"": ""17:30"" + }, + { + ""day"": ""sunday"", + ""start_time"": ""11:00"", + ""end_time"": ""17:40"" + } + ] + } + ] + } + ")); + + var actualResponse = this.Client.GetAvailabilityRules(); + + var expectedResponse = new[] + { + new AvailabilityRule + { + AvailabilityRuleId = "default", + TimeZoneId = "America/Chicago", + CalendarIds = new[] { "cal_n23kjnwrw2_jsdfjksn234" }, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "09:30", + EndTime = "12:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "14:00", + EndTime = "17:00", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "wednesday", + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }, + new AvailabilityRule + { + AvailabilityRuleId = "another_rule", + TimeZoneId = "Europe/London", + CalendarIds = new[] + { + "cal_n23kjnwrw2_jsdfjksn234", + "cal_n23kjnwrw2_th53tksn567", + }, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = "saturday", + StartTime = "09:00", + EndTime = "17:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "sunday", + StartTime = "11:00", + EndTime = "17:40", + }, + }, + }, + }; + + Assert.AreEqual(expectedResponse, actualResponse); + } + } +} diff --git a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs new file mode 100644 index 0000000..798e4f3 --- /dev/null +++ b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs @@ -0,0 +1,127 @@ +namespace Cronofy.Test.CronofyAccountClientTests +{ + using NUnit.Framework; + + internal sealed class UpsertAvailabilityRule : Base + { + [Test] + public void CanUpsertAvailabilityRule() + { + this.Http.Stub( + HttpPost + .Url("https://api.cronofy.com/v1/availability_rules") + .RequestHeader("Authorization", "Bearer " + AccessToken) + .JsonRequest(@" + { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + } + ") + .ResponseCode(200) + .ResponseBody(@" + { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + } + ")); + + var actualResponse = this.Client.UpsertAvailabilityRule(new Requests.UpsertAvailabilityRuleRequest + { + AvailabilityRuleId = "default", + TimeZoneId = "America/Chicago", + CalendarIds = new[] { "cal_n23kjnwrw2_jsdfjksn234" }, + WeeklyPeriods = new[] + { + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "monday", + StartTime = "09:30", + EndTime = "12:30", + }, + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "monday", + StartTime = "14:00", + EndTime = "17:00", + }, + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "wednesday", + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }); + + var expectedResponse = new AvailabilityRule + { + AvailabilityRuleId = "default", + TimeZoneId = "America/Chicago", + CalendarIds = new[] { "cal_n23kjnwrw2_jsdfjksn234" }, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "09:30", + EndTime = "12:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "monday", + StartTime = "14:00", + EndTime = "17:00", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = "wednesday", + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }; + + Assert.AreEqual(expectedResponse, actualResponse); + } + } +} From c79993abc9c999ac37b789376a6404c461236fca Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 10:00:35 +0100 Subject: [PATCH 2/8] Upsert and get responses should be nested in a top level object rather than deserialized directly --- src/Cronofy/AvailabilityRule.cs | 2 +- src/Cronofy/CronofyAccountClient.cs | 8 +-- .../Responses/GetAvailabilityRuleResponse.cs | 21 ++++++++ .../ListAvailabilityRulesResponse.cs | 4 +- .../UpsertAvailabilityRuleResponse.cs | 21 ++++++++ .../GetAvailabilityRule.cs | 50 ++++++++++--------- .../UpsertAvailabilityRule.cs | 46 +++++++++-------- 7 files changed, 99 insertions(+), 53 deletions(-) create mode 100644 src/Cronofy/Responses/GetAvailabilityRuleResponse.cs create mode 100644 src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs diff --git a/src/Cronofy/AvailabilityRule.cs b/src/Cronofy/AvailabilityRule.cs index c63039e..51913ff 100644 --- a/src/Cronofy/AvailabilityRule.cs +++ b/src/Cronofy/AvailabilityRule.cs @@ -92,7 +92,7 @@ public override string ToString() this.AvailabilityRuleId, this.TimeZoneId, this.CalendarIds, - this.WeeklyPeriods); + string.Join(", ", this.WeeklyPeriods.Select(weeklyPeriod => weeklyPeriod.ToString()))); } /// diff --git a/src/Cronofy/CronofyAccountClient.cs b/src/Cronofy/CronofyAccountClient.cs index e9bd39e..6aa927a 100644 --- a/src/Cronofy/CronofyAccountClient.cs +++ b/src/Cronofy/CronofyAccountClient.cs @@ -571,9 +571,9 @@ public AvailabilityRule GetAvailabilityRule(string availabilityRuleId) request.Url = string.Format(this.UrlProvider.AvailabilityRuleUrl, availabilityRuleId); request.AddOAuthAuthorization(this.AccessToken); - var response = this.HttpClient.GetJsonResponse(request); + var response = this.HttpClient.GetJsonResponse(request); - return response.ToAvailabilityRule(); + return response.AvailabilityRule.ToAvailabilityRule(); } /// @@ -602,9 +602,9 @@ public AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest ups request.AddOAuthAuthorization(this.AccessToken); request.SetJsonBody(upsertAvailabilityRuleRequest); - var response = this.HttpClient.GetJsonResponse(request); + var response = this.HttpClient.GetJsonResponse(request); - return response.ToAvailabilityRule(); + return response.AvailabilityRule.ToAvailabilityRule(); } /// diff --git a/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs b/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs new file mode 100644 index 0000000..a3aa9b9 --- /dev/null +++ b/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs @@ -0,0 +1,21 @@ +namespace Cronofy.Responses +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// Class for the deserialization of a get availability rule response. + /// + internal sealed class GetAvailabilityRulesResponse + { + /// + /// Gets or sets the availability rule. + /// + /// + /// The availability rule. + /// + [JsonProperty("availability_rule")] + public AvailabilityRuleResponse AvailabilityRule { get; set; } + } +} diff --git a/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs b/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs index 566ff26..17f2ff6 100644 --- a/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs +++ b/src/Cronofy/Responses/ListAvailabilityRulesResponse.cs @@ -10,10 +10,10 @@ namespace Cronofy.Responses internal sealed class ListAvailabilityRulesResponse { /// - /// Gets or sets the weekly recurring periods for the availability rule. + /// Gets or sets the list of discovered availability rules. /// /// - /// The weekly recurring periods for the availability rule. + /// The list of discovered availability rules. /// [JsonProperty("availability_rules")] public IEnumerable AvailabilityRules { get; set; } diff --git a/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs b/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs new file mode 100644 index 0000000..c9e4d83 --- /dev/null +++ b/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs @@ -0,0 +1,21 @@ +namespace Cronofy.Responses +{ + using System; + using System.Collections.Generic; + using Newtonsoft.Json; + + /// + /// Class for the deserialization of an upsert availability rules response. + /// + internal sealed class UpsertAvailabilityRulesResponse + { + /// + /// Gets or sets the created or updated availability rule. + /// + /// + /// The created or updated availability rule. + /// + [JsonProperty("availability_rule")] + public AvailabilityRuleResponse AvailabilityRule { get; set; } + } +} diff --git a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs index 0685045..8021856 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs @@ -16,30 +16,32 @@ public void CanGetAvailabilityRule() .ResponseCode(200) .ResponseBodyFormat( @" - {{ - ""availability_rule_id"": ""{0}"", - ""tzid"": ""America/Chicago"", - ""calendar_ids"": [ - ""cal_n23kjnwrw2_jsdfjksn234"" - ], - ""weekly_periods"": [ - {{ - ""day"": ""monday"", - ""start_time"": ""09:30"", - ""end_time"": ""12:30"" - }}, - {{ - ""day"": ""monday"", - ""start_time"": ""14:00"", - ""end_time"": ""17:00"" - }}, - {{ - ""day"": ""wednesday"", - ""start_time"": ""09:30"", - ""end_time"": ""12:30"" - }} - ] - }} + {{ + ""availability_rule"": {{ + ""availability_rule_id"": ""{0}"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + {{ + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }}, + {{ + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }}, + {{ + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }} + ] + }} + }} ", AvailabilityRuleId)); var actualResponse = this.Client.GetAvailabilityRule(AvailabilityRuleId); diff --git a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs index 798e4f3..a106d96 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs @@ -40,28 +40,30 @@ public void CanUpsertAvailabilityRule() .ResponseCode(200) .ResponseBody(@" { - ""availability_rule_id"": ""default"", - ""tzid"": ""America/Chicago"", - ""calendar_ids"": [ - ""cal_n23kjnwrw2_jsdfjksn234"" - ], - ""weekly_periods"": [ - { - ""day"": ""monday"", - ""start_time"": ""09:30"", - ""end_time"": ""12:30"" - }, - { - ""day"": ""monday"", - ""start_time"": ""14:00"", - ""end_time"": ""17:00"" - }, - { - ""day"": ""wednesday"", - ""start_time"": ""09:30"", - ""end_time"": ""12:30"" - } - ] + ""availability_rule"": { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""calendar_ids"": [ + ""cal_n23kjnwrw2_jsdfjksn234"" + ], + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + } } ")); From 41aef54d24b8dc2e23337e9c69e341c54576d2ba Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 10:00:53 +0100 Subject: [PATCH 3/8] Add an example showing usage of the availability rules SDKs --- src/Cronofy.Example/Program.cs | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/src/Cronofy.Example/Program.cs b/src/Cronofy.Example/Program.cs index a2b4552..b58e15b 100644 --- a/src/Cronofy.Example/Program.cs +++ b/src/Cronofy.Example/Program.cs @@ -34,6 +34,11 @@ public static void Main(string[] args) AttachmentsExample(); return; } + else if (args.Any(t => t == "availability-rules")) + { + AvailabilityRulesExample(); + return; + } Console.Write("Enter access token: "); var accessToken = Console.ReadLine(); @@ -241,6 +246,90 @@ private static void AttachmentsExample() Console.ReadLine(); } + /// + /// Availability rules usage example. + /// + private static void AvailabilityRulesExample() + { + Console.Write("Enter access token: "); + var accessToken = Console.ReadLine(); + + Console.WriteLine(); + var client = new CronofyAccountClient(accessToken); + + FetchAndPrintCalendars(client); + + Console.Write("Enter calendar ID: "); + var calendarId = Console.ReadLine(); + Console.WriteLine(); + + Console.WriteLine("Creating an example availability rule"); + Console.WriteLine(); + + const string AvailabilityRuleId = "CSharpExampleAvailabilityRule"; + + client.UpsertAvailabilityRule(new Requests.UpsertAvailabilityRuleRequest + { + AvailabilityRuleId = AvailabilityRuleId, + TimeZoneId = "America/Chicago", + CalendarIds = new[] { calendarId }, + WeeklyPeriods = new[] + { + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "monday", + StartTime = "09:30", + EndTime = "12:30", + }, + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "monday", + StartTime = "14:00", + EndTime = "17:00", + }, + new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + { + Day = "wednesday", + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }); + + Console.WriteLine("Availability rule created"); + Console.WriteLine(); + + Console.WriteLine("Fetching created availability rule..."); + var availabilityRule = client.GetAvailabilityRule(AvailabilityRuleId); + + Console.WriteLine(); + Console.WriteLine(availabilityRule.ToString()); + Console.WriteLine(); + + + Console.WriteLine("Fetching all availability rules..."); + var availabilityRules = client.GetAvailabilityRules(); + + Console.WriteLine(); + + foreach (var rule in availabilityRules) + { + Console.WriteLine(rule.ToString()); + } + + Console.WriteLine(); + + Console.WriteLine("Press enter to delete the example rule..."); + Console.ReadLine(); + + client.DeleteAvailabilityRule(AvailabilityRuleId); + Console.WriteLine("Availability rule deleted"); + Console.WriteLine(); + + Console.WriteLine("Press enter to continue..."); + Console.ReadLine(); + } + /// /// Fetches a list of all of the users calendars and prints a summary to the console. /// From 447a3b7272682320d601970ebcc5cfae25025a18 Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 10:17:04 +0100 Subject: [PATCH 4/8] Ensure filename and class names match --- src/Cronofy/CronofyAccountClient.cs | 4 ++-- src/Cronofy/Responses/GetAvailabilityRuleResponse.cs | 2 +- src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cronofy/CronofyAccountClient.cs b/src/Cronofy/CronofyAccountClient.cs index 6aa927a..e2f9092 100644 --- a/src/Cronofy/CronofyAccountClient.cs +++ b/src/Cronofy/CronofyAccountClient.cs @@ -571,7 +571,7 @@ public AvailabilityRule GetAvailabilityRule(string availabilityRuleId) request.Url = string.Format(this.UrlProvider.AvailabilityRuleUrl, availabilityRuleId); request.AddOAuthAuthorization(this.AccessToken); - var response = this.HttpClient.GetJsonResponse(request); + var response = this.HttpClient.GetJsonResponse(request); return response.AvailabilityRule.ToAvailabilityRule(); } @@ -602,7 +602,7 @@ public AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest ups request.AddOAuthAuthorization(this.AccessToken); request.SetJsonBody(upsertAvailabilityRuleRequest); - var response = this.HttpClient.GetJsonResponse(request); + var response = this.HttpClient.GetJsonResponse(request); return response.AvailabilityRule.ToAvailabilityRule(); } diff --git a/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs b/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs index a3aa9b9..1a5306d 100644 --- a/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs +++ b/src/Cronofy/Responses/GetAvailabilityRuleResponse.cs @@ -7,7 +7,7 @@ namespace Cronofy.Responses /// /// Class for the deserialization of a get availability rule response. /// - internal sealed class GetAvailabilityRulesResponse + internal sealed class GetAvailabilityRuleResponse { /// /// Gets or sets the availability rule. diff --git a/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs b/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs index c9e4d83..4147126 100644 --- a/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs +++ b/src/Cronofy/Responses/UpsertAvailabilityRuleResponse.cs @@ -7,7 +7,7 @@ namespace Cronofy.Responses /// /// Class for the deserialization of an upsert availability rules response. /// - internal sealed class UpsertAvailabilityRulesResponse + internal sealed class UpsertAvailabilityRuleResponse { /// /// Gets or sets the created or updated availability rule. From cd4d5929586629c0ff87b78821441374a1379f3c Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 14:15:19 +0100 Subject: [PATCH 5/8] Use System.DayOfWeek instead of a string representation of the day --- src/Cronofy.Example/Program.cs | 15 +++-- src/Cronofy/AvailabilityRule.cs | 2 +- src/Cronofy/CronofyAccountClient.cs | 10 ++-- src/Cronofy/ICronofyAccountClient.cs | 8 +-- .../Requests/UpsertAvailabilityRuleRequest.cs | 59 +++++++++++++++++++ .../Responses/AvailabilityRuleResponse.cs | 30 +++++++++- .../GetAvailabilityRule.cs | 7 ++- .../ListAvailabilityRules.cs | 11 ++-- .../UpsertAvailabilityRule.cs | 41 +++---------- 9 files changed, 124 insertions(+), 59 deletions(-) diff --git a/src/Cronofy.Example/Program.cs b/src/Cronofy.Example/Program.cs index b58e15b..9a5610f 100644 --- a/src/Cronofy.Example/Program.cs +++ b/src/Cronofy.Example/Program.cs @@ -268,28 +268,28 @@ private static void AvailabilityRulesExample() const string AvailabilityRuleId = "CSharpExampleAvailabilityRule"; - client.UpsertAvailabilityRule(new Requests.UpsertAvailabilityRuleRequest + client.UpsertAvailabilityRule(new AvailabilityRule { AvailabilityRuleId = AvailabilityRuleId, TimeZoneId = "America/Chicago", CalendarIds = new[] { calendarId }, WeeklyPeriods = new[] { - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "09:30", EndTime = "12:30", }, - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "14:00", EndTime = "17:00", }, - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod + new AvailabilityRule.WeeklyPeriod { - Day = "wednesday", + Day = DayOfWeek.Wednesday, StartTime = "09:30", EndTime = "12:30", }, @@ -306,7 +306,6 @@ private static void AvailabilityRulesExample() Console.WriteLine(availabilityRule.ToString()); Console.WriteLine(); - Console.WriteLine("Fetching all availability rules..."); var availabilityRules = client.GetAvailabilityRules(); diff --git a/src/Cronofy/AvailabilityRule.cs b/src/Cronofy/AvailabilityRule.cs index 51913ff..82f0b00 100644 --- a/src/Cronofy/AvailabilityRule.cs +++ b/src/Cronofy/AvailabilityRule.cs @@ -106,7 +106,7 @@ public class WeeklyPeriod /// /// The week day the period applies to. /// - public string Day { get; set; } + public DayOfWeek Day { get; set; } /// /// Gets or sets the time of day the period should start. diff --git a/src/Cronofy/CronofyAccountClient.cs b/src/Cronofy/CronofyAccountClient.cs index e2f9092..0546407 100644 --- a/src/Cronofy/CronofyAccountClient.cs +++ b/src/Cronofy/CronofyAccountClient.cs @@ -563,7 +563,7 @@ public string GetConferencingServiceAuthorizationUrl(ConferencingServiceAuthoriz /// public AvailabilityRule GetAvailabilityRule(string availabilityRuleId) { - Preconditions.NotEmpty("availabilityRuleId", availabilityRuleId); + Preconditions.NotEmpty(nameof(availabilityRuleId), availabilityRuleId); var request = new HttpRequest(); @@ -591,15 +591,17 @@ public IEnumerable GetAvailabilityRules() } /// - public AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest upsertAvailabilityRuleRequest) + public AvailabilityRule UpsertAvailabilityRule(AvailabilityRule availabilityRule) { - Preconditions.NotNull("upsertAvailabilityRuleRequest", upsertAvailabilityRuleRequest); + Preconditions.NotNull(nameof(availabilityRule), availabilityRule); var request = new HttpRequest(); request.Method = "POST"; request.Url = this.UrlProvider.AvailabilityRulesUrl; request.AddOAuthAuthorization(this.AccessToken); + + var upsertAvailabilityRuleRequest = UpsertAvailabilityRuleRequest.FromAvailabilityRule(availabilityRule); request.SetJsonBody(upsertAvailabilityRuleRequest); var response = this.HttpClient.GetJsonResponse(request); @@ -610,7 +612,7 @@ public AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest ups /// public void DeleteAvailabilityRule(string availabilityRuleId) { - Preconditions.NotEmpty("availabilityRuleId", availabilityRuleId); + Preconditions.NotEmpty(nameof(availabilityRuleId), availabilityRuleId); var request = new HttpRequest(); diff --git a/src/Cronofy/ICronofyAccountClient.cs b/src/Cronofy/ICronofyAccountClient.cs index f94a9ca..edeb7bc 100644 --- a/src/Cronofy/ICronofyAccountClient.cs +++ b/src/Cronofy/ICronofyAccountClient.cs @@ -588,17 +588,17 @@ public interface ICronofyAccountClient : ICronofyUserInfoClient /// /// Creates or updates an availability rule. /// - /// - /// The parameters for the request, must not be null. + /// + /// The availability rule to upsert, must not be null. /// /// The created or updated availability rule. /// - /// Thrown if is null. + /// Thrown if is null. /// /// /// Thrown if an error is encountered whilst making the request. /// - AvailabilityRule UpsertAvailabilityRule(UpsertAvailabilityRuleRequest upsertAvailabilityRuleRequest); + AvailabilityRule UpsertAvailabilityRule(AvailabilityRule availabilityRule); /// /// Deletes an availability rule for the authenticated account. diff --git a/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs index ca35ed1..09c496b 100644 --- a/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs +++ b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs @@ -46,6 +46,22 @@ public sealed class UpsertAvailabilityRuleRequest [JsonProperty("weekly_periods")] public IEnumerable WeeklyPeriods { get; set; } + /// + /// Creates an upsert request from an existing availability rule. + /// + /// Availability rule to create this upsert request from. + /// An upsert request for the given rule. + public static UpsertAvailabilityRuleRequest FromAvailabilityRule(AvailabilityRule availabilityRule) + { + return new UpsertAvailabilityRuleRequest + { + AvailabilityRuleId = availabilityRule.AvailabilityRuleId, + TimeZoneId = availabilityRule.TimeZoneId, + CalendarIds = availabilityRule.CalendarIds.ToArray(), + WeeklyPeriods = availabilityRule.WeeklyPeriods.Select(WeeklyPeriod.FromWeeklyPeriod).ToArray(), + }; + } + /// /// Class for the serialization of a weekly period within an availability rule. /// @@ -77,6 +93,49 @@ public sealed class WeeklyPeriod /// [JsonProperty("end_time")] public string EndTime { get; set; } + + /// + /// Creates an upset weekly period request from a given weekly period. + /// + /// The weekly period to copy from. + /// The weekly period upsert request. + public static WeeklyPeriod FromWeeklyPeriod(AvailabilityRule.WeeklyPeriod weeklyPeriod) + { + return new WeeklyPeriod + { + Day = ToDayString(weeklyPeriod.Day), + StartTime = weeklyPeriod.StartTime, + EndTime = weeklyPeriod.EndTime, + }; + } + + /// + /// Converts a day of the week to its string representation. + /// + /// The day of the week. + /// The string representation of the day of the week. + private static string ToDayString(DayOfWeek day) + { + switch (day) + { + case DayOfWeek.Monday: + return "monday"; + case DayOfWeek.Tuesday: + return "tuesday"; + case DayOfWeek.Wednesday: + return "wednesday"; + case DayOfWeek.Thursday: + return "thursday"; + case DayOfWeek.Friday: + return "friday"; + case DayOfWeek.Saturday: + return "saturday"; + case DayOfWeek.Sunday: + return "sunday"; + default: + throw new ArgumentOutOfRangeException(nameof(day), "Unexpected day"); + } + } } } } diff --git a/src/Cronofy/Responses/AvailabilityRuleResponse.cs b/src/Cronofy/Responses/AvailabilityRuleResponse.cs index 5d16643..963a5d5 100644 --- a/src/Cronofy/Responses/AvailabilityRuleResponse.cs +++ b/src/Cronofy/Responses/AvailabilityRuleResponse.cs @@ -105,11 +105,39 @@ public AvailabilityRule.WeeklyPeriod ToWeeklyPeriod() { return new AvailabilityRule.WeeklyPeriod { - Day = this.Day, + Day = ToDayOfWeek(this.Day), StartTime = this.StartTime, EndTime = this.EndTime, }; } + + /// + /// Converts a day string to a day of the week representation. + /// + /// The string representation of the day of the week. + /// The day of the week represented by the string. + private static DayOfWeek ToDayOfWeek(string day) + { + switch (day) + { + case "monday": + return DayOfWeek.Monday; + case "tuesday": + return DayOfWeek.Tuesday; + case "wednesday": + return DayOfWeek.Wednesday; + case "thursday": + return DayOfWeek.Thursday; + case "friday": + return DayOfWeek.Friday; + case "saturday": + return DayOfWeek.Saturday; + case "sunday": + return DayOfWeek.Sunday; + default: + throw new ArgumentOutOfRangeException(nameof(day), "Unexpected day"); + } + } } } } diff --git a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs index 8021856..09b7576 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs @@ -1,5 +1,6 @@ namespace Cronofy.Test.CronofyAccountClientTests { + using System; using NUnit.Framework; internal sealed class GetAvailabilityRule : Base @@ -55,19 +56,19 @@ public void CanGetAvailabilityRule() { new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "09:30", EndTime = "12:30", }, new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "14:00", EndTime = "17:00", }, new AvailabilityRule.WeeklyPeriod { - Day = "wednesday", + Day = DayOfWeek.Wednesday, StartTime = "09:30", EndTime = "12:30", }, diff --git a/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs index 6d64214..9899e14 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs @@ -1,5 +1,6 @@ namespace Cronofy.Test.CronofyAccountClientTests { + using System; using NUnit.Framework; internal sealed class ListAvailabilityRules : Base @@ -76,19 +77,19 @@ public void CanListAvailabilityRules() { new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "09:30", EndTime = "12:30", }, new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "14:00", EndTime = "17:00", }, new AvailabilityRule.WeeklyPeriod { - Day = "wednesday", + Day = DayOfWeek.Wednesday, StartTime = "09:30", EndTime = "12:30", }, @@ -107,13 +108,13 @@ public void CanListAvailabilityRules() { new AvailabilityRule.WeeklyPeriod { - Day = "saturday", + Day = DayOfWeek.Saturday, StartTime = "09:00", EndTime = "17:30", }, new AvailabilityRule.WeeklyPeriod { - Day = "sunday", + Day = DayOfWeek.Sunday, StartTime = "11:00", EndTime = "17:40", }, diff --git a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs index a106d96..2cb542a 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs @@ -1,5 +1,6 @@ namespace Cronofy.Test.CronofyAccountClientTests { + using System; using NUnit.Framework; internal sealed class UpsertAvailabilityRule : Base @@ -67,35 +68,7 @@ public void CanUpsertAvailabilityRule() } ")); - var actualResponse = this.Client.UpsertAvailabilityRule(new Requests.UpsertAvailabilityRuleRequest - { - AvailabilityRuleId = "default", - TimeZoneId = "America/Chicago", - CalendarIds = new[] { "cal_n23kjnwrw2_jsdfjksn234" }, - WeeklyPeriods = new[] - { - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod - { - Day = "monday", - StartTime = "09:30", - EndTime = "12:30", - }, - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod - { - Day = "monday", - StartTime = "14:00", - EndTime = "17:00", - }, - new Requests.UpsertAvailabilityRuleRequest.WeeklyPeriod - { - Day = "wednesday", - StartTime = "09:30", - EndTime = "12:30", - }, - }, - }); - - var expectedResponse = new AvailabilityRule + var updatedAvailabilityRuleState = new AvailabilityRule { AvailabilityRuleId = "default", TimeZoneId = "America/Chicago", @@ -104,26 +77,28 @@ public void CanUpsertAvailabilityRule() { new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "09:30", EndTime = "12:30", }, new AvailabilityRule.WeeklyPeriod { - Day = "monday", + Day = DayOfWeek.Monday, StartTime = "14:00", EndTime = "17:00", }, new AvailabilityRule.WeeklyPeriod { - Day = "wednesday", + Day = DayOfWeek.Wednesday, StartTime = "09:30", EndTime = "12:30", }, }, }; - Assert.AreEqual(expectedResponse, actualResponse); + var actualResponse = this.Client.UpsertAvailabilityRule(updatedAvailabilityRuleState); + + Assert.AreEqual(updatedAvailabilityRuleState, actualResponse); } } } From 4cee8ffcd8f2b3f8cc52d9ad94820fef45129a03 Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 14:21:29 +0100 Subject: [PATCH 6/8] Use a newer version of .NET for the example app --- src/Cronofy.Example/Cronofy.Example.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cronofy.Example/Cronofy.Example.csproj b/src/Cronofy.Example/Cronofy.Example.csproj index 28d8c3d..4c525d0 100644 --- a/src/Cronofy.Example/Cronofy.Example.csproj +++ b/src/Cronofy.Example/Cronofy.Example.csproj @@ -23,7 +23,7 @@ Exe - netcoreapp3.1 + net7 false From 11080c757477245c0ce43a0ef09b405fbaa930ba Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 15:13:24 +0100 Subject: [PATCH 7/8] Handle null/missing calendar id arrays --- src/Cronofy/AvailabilityRule.cs | 2 +- .../Requests/UpsertAvailabilityRuleRequest.cs | 2 +- .../Responses/AvailabilityRuleResponse.cs | 2 +- .../GetAvailabilityRule.cs | 68 ++++++++++++++ .../ListAvailabilityRules.cs | 26 ++++++ .../UpsertAvailabilityRule.cs | 90 +++++++++++++++++++ 6 files changed, 187 insertions(+), 3 deletions(-) diff --git a/src/Cronofy/AvailabilityRule.cs b/src/Cronofy/AvailabilityRule.cs index 82f0b00..bf22a18 100644 --- a/src/Cronofy/AvailabilityRule.cs +++ b/src/Cronofy/AvailabilityRule.cs @@ -79,7 +79,7 @@ public bool Equals(AvailabilityRule other) { return this.AvailabilityRuleId == other.AvailabilityRuleId && this.TimeZoneId == other.TimeZoneId && - this.CalendarIds.SequenceEqual(other.CalendarIds) && + ((this.CalendarIds == null && other.CalendarIds == null) || (this.CalendarIds != null && other.CalendarIds != null && this.CalendarIds.SequenceEqual(other.CalendarIds))) && this.WeeklyPeriods.SequenceEqual(other.WeeklyPeriods); } diff --git a/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs index 09c496b..c26784f 100644 --- a/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs +++ b/src/Cronofy/Requests/UpsertAvailabilityRuleRequest.cs @@ -57,7 +57,7 @@ public static UpsertAvailabilityRuleRequest FromAvailabilityRule(AvailabilityRul { AvailabilityRuleId = availabilityRule.AvailabilityRuleId, TimeZoneId = availabilityRule.TimeZoneId, - CalendarIds = availabilityRule.CalendarIds.ToArray(), + CalendarIds = availabilityRule.CalendarIds?.ToArray(), WeeklyPeriods = availabilityRule.WeeklyPeriods.Select(WeeklyPeriod.FromWeeklyPeriod).ToArray(), }; } diff --git a/src/Cronofy/Responses/AvailabilityRuleResponse.cs b/src/Cronofy/Responses/AvailabilityRuleResponse.cs index 963a5d5..5726540 100644 --- a/src/Cronofy/Responses/AvailabilityRuleResponse.cs +++ b/src/Cronofy/Responses/AvailabilityRuleResponse.cs @@ -58,7 +58,7 @@ public AvailabilityRule ToAvailabilityRule() { AvailabilityRuleId = this.AvailabilityRuleId, TimeZoneId = this.TimeZoneId, - CalendarIds = this.CalendarIds.ToArray(), + CalendarIds = this.CalendarIds?.ToArray(), WeeklyPeriods = this.WeeklyPeriods.Select(weeklyPeriod => weeklyPeriod.ToWeeklyPeriod()).ToArray(), }; } diff --git a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs index 09b7576..4f6d199 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/GetAvailabilityRule.cs @@ -77,5 +77,73 @@ public void CanGetAvailabilityRule() Assert.AreEqual(expectedResponse, actualResponse); } + + [Test] + public void CanGetAvailabilityRuleWithMissingCalendarIds() + { + this.Http.Stub( + HttpGet + .Url("https://api.cronofy.com/v1/availability_rules/" + AvailabilityRuleId) + .RequestHeader("Authorization", "Bearer " + AccessToken) + .ResponseCode(200) + .ResponseBodyFormat( + @" + {{ + ""availability_rule"": {{ + ""availability_rule_id"": ""{0}"", + ""tzid"": ""America/Chicago"", + ""weekly_periods"": [ + {{ + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }}, + {{ + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }}, + {{ + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }} + ] + }} + }} + ", AvailabilityRuleId)); + + var actualResponse = this.Client.GetAvailabilityRule(AvailabilityRuleId); + + var expectedResponse = new AvailabilityRule + { + AvailabilityRuleId = AvailabilityRuleId, + TimeZoneId = "America/Chicago", + CalendarIds = null, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Monday, + StartTime = "09:30", + EndTime = "12:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Monday, + StartTime = "14:00", + EndTime = "17:00", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Wednesday, + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }; + + Assert.AreEqual(expectedResponse, actualResponse); + } } } diff --git a/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs index 9899e14..a378a2e 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/ListAvailabilityRules.cs @@ -59,6 +59,17 @@ public void CanListAvailabilityRules() ""end_time"": ""17:40"" } ] + }, + { + ""availability_rule_id"": ""null_calendar_ids"", + ""tzid"": ""Europe/London"", + ""weekly_periods"": [ + { + ""day"": ""thursday"", + ""start_time"": ""09:00"", + ""end_time"": ""17:30"" + } + ] } ] } @@ -120,6 +131,21 @@ public void CanListAvailabilityRules() }, }, }, + new AvailabilityRule + { + AvailabilityRuleId = "null_calendar_ids", + TimeZoneId = "Europe/London", + CalendarIds = null, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Thursday, + StartTime = "09:00", + EndTime = "17:30", + }, + }, + }, }; Assert.AreEqual(expectedResponse, actualResponse); diff --git a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs index 2cb542a..2fb5aba 100644 --- a/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs +++ b/test/Cronofy.Test/CronofyAccountClientTests/UpsertAvailabilityRule.cs @@ -100,5 +100,95 @@ public void CanUpsertAvailabilityRule() Assert.AreEqual(updatedAvailabilityRuleState, actualResponse); } + + [Test] + public void CanUpsertAvailabilityRuleWithMissingCalendarIds() + { + this.Http.Stub( + HttpPost + .Url("https://api.cronofy.com/v1/availability_rules") + .RequestHeader("Authorization", "Bearer " + AccessToken) + .JsonRequest(@" + { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + } + ") + .ResponseCode(200) + .ResponseBody(@" + { + ""availability_rule"": { + ""availability_rule_id"": ""default"", + ""tzid"": ""America/Chicago"", + ""weekly_periods"": [ + { + ""day"": ""monday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + }, + { + ""day"": ""monday"", + ""start_time"": ""14:00"", + ""end_time"": ""17:00"" + }, + { + ""day"": ""wednesday"", + ""start_time"": ""09:30"", + ""end_time"": ""12:30"" + } + ] + } + } + ")); + + var updatedAvailabilityRuleState = new AvailabilityRule + { + AvailabilityRuleId = "default", + TimeZoneId = "America/Chicago", + CalendarIds = null, + WeeklyPeriods = new[] + { + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Monday, + StartTime = "09:30", + EndTime = "12:30", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Monday, + StartTime = "14:00", + EndTime = "17:00", + }, + new AvailabilityRule.WeeklyPeriod + { + Day = DayOfWeek.Wednesday, + StartTime = "09:30", + EndTime = "12:30", + }, + }, + }; + + var actualResponse = this.Client.UpsertAvailabilityRule(updatedAvailabilityRuleState); + + Assert.AreEqual(updatedAvailabilityRuleState, actualResponse); + } } } From b8f4284dffb08e7cdfbb3c7d9aa3cf6f73557a4b Mon Sep 17 00:00:00 2001 From: Matthew Wade Date: Wed, 9 Oct 2024 15:20:46 +0100 Subject: [PATCH 8/8] Also handle the possible null calendar id arrays in ToString --- src/Cronofy/AvailabilityRule.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cronofy/AvailabilityRule.cs b/src/Cronofy/AvailabilityRule.cs index bf22a18..401b9d6 100644 --- a/src/Cronofy/AvailabilityRule.cs +++ b/src/Cronofy/AvailabilityRule.cs @@ -87,11 +87,11 @@ public bool Equals(AvailabilityRule other) public override string ToString() { return string.Format( - "<{0} AvailabilityRuleId={1}, TimeZoneId={2}, CalendarIds={3}, WeeklyPeriods={4}>", + "<{0} AvailabilityRuleId={1}, TimeZoneId={2}, CalendarIds={3}, WeeklyPeriods=[{4}]>", this.GetType(), this.AvailabilityRuleId, this.TimeZoneId, - this.CalendarIds, + this.CalendarIds == null ? "null" : string.Format("[{0}]", string.Join(", ", this.CalendarIds)), string.Join(", ", this.WeeklyPeriods.Select(weeklyPeriod => weeklyPeriod.ToString()))); }