cronofy 0.25.1 → 0.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: aa2dbaa1fff22d1bf386ea8510b33592ae43307b
4
- data.tar.gz: 98f437522497ffa946e62e1d860d9ddbbbcd5726
3
+ metadata.gz: 62d037f0b84f5f60661b7875c8bf2645df8a5b94
4
+ data.tar.gz: fbbb34833ed05e6ad74375dff707a73ae0138458
5
5
  SHA512:
6
- metadata.gz: 8526a9632f28225092530b0250af075529bca6607260897f9b599438d846cf4c624c5d86d42a4ae59359d71e7e2047101a1aff0b6b6ddb5e02f7b2f74b9e4a53
7
- data.tar.gz: dd3774efc5c33c90001829391c7bf8a30c3636a4308485e5ffa3ca5e9ddfea2a2b224177c318cf7eef1a6b6b5af120aba8cebab79c1475e1165b0a05a6b0b801
6
+ metadata.gz: 923d240d65bb915cd34560f41c0752ec39e3bed611b000c5fea4c9648afe31eccce96b5e19a16a9b5e28b9b3b135a56b621df916c7c8100fc00cbe2e6d12869d
7
+ data.tar.gz: 4d5bfa47913f8439892f10c458dec0464701ccaeb3f0561e2d6bf01c9b479ce7b01d5411464f06a9d02583163d5b31e23f31e186384773c223d9046998c99f12
@@ -1,3 +1,7 @@
1
+ ## [0.26.0]
2
+
3
+ * Support for batch endpoint [#53]
4
+
1
5
  ## [0.25.1]
2
6
 
3
7
  * Support for Cancelling Smart Invites [#55]
@@ -91,6 +95,7 @@
91
95
  [0.24.1]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.24.1
92
96
  [0.25.0]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.25.0
93
97
  [0.25.1]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.25.1
98
+ [0.26.0]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.26.0
94
99
 
95
100
  [#13]: https://github.com/cronofy/cronofy-ruby/pull/13
96
101
  [#16]: https://github.com/cronofy/cronofy-ruby/pull/16
@@ -115,4 +120,5 @@
115
120
  [#49]: https://github.com/cronofy/cronofy-ruby/pull/49
116
121
  [#50]: https://github.com/cronofy/cronofy-ruby/pull/50
117
122
  [#52]: https://github.com/cronofy/cronofy-ruby/pull/52
123
+ [#53]: https://github.com/cronofy/cronofy-ruby/pull/53
118
124
  [#55]: https://github.com/cronofy/cronofy-ruby/pull/55
@@ -3,6 +3,7 @@ require "cronofy/errors"
3
3
  require "cronofy/types"
4
4
  require "cronofy/api_key"
5
5
  require "cronofy/auth"
6
+ require "cronofy/time_encoding"
6
7
  require "cronofy/client"
7
8
  require "cronofy/response_parser"
8
9
 
@@ -1,6 +1,8 @@
1
1
  module Cronofy
2
2
  # Public: Primary class for interacting with the Cronofy API.
3
3
  class Client
4
+ include TimeEncoding
5
+
4
6
  # Public: The scope to request if none is explicitly specified by the
5
7
  # caller.
6
8
  DEFAULT_OAUTH_SCOPE = %w{
@@ -308,6 +310,75 @@ module Cronofy
308
310
  nil
309
311
  end
310
312
 
313
+ class BatchBuilder
314
+ include TimeEncoding
315
+
316
+ def initialize
317
+ @entries = []
318
+ end
319
+
320
+ def upsert_event(calendar_id, event)
321
+ data = event.dup
322
+
323
+ data[:start] = encode_event_time(data[:start])
324
+ data[:end] = encode_event_time(data[:end])
325
+
326
+ post "/v1/calendars/#{calendar_id}/events", data
327
+ end
328
+
329
+ alias_method :create_or_update_event, :upsert_event
330
+
331
+ def delete_event(calendar_id, event_id)
332
+ delete "/v1/calendars/#{calendar_id}/events", event_id: event_id
333
+ end
334
+
335
+ def delete_external_event(calendar_id, event_uid)
336
+ delete "/v1/calendars/#{calendar_id}/events", event_uid: event_uid
337
+ end
338
+
339
+ def add_entry(args)
340
+ @entries << BatchEntryRequest.new(args)
341
+ nil
342
+ end
343
+
344
+ def build
345
+ @entries.dup
346
+ end
347
+
348
+ private
349
+
350
+ def delete(relative_url, data)
351
+ add_entry(method: "DELETE", relative_url: relative_url, data: data)
352
+ end
353
+
354
+ def post(relative_url, data)
355
+ add_entry(method: "POST", relative_url: relative_url, data: data)
356
+ end
357
+ end
358
+
359
+ def batch
360
+ yield builder = BatchBuilder.new
361
+
362
+ requests = builder.build
363
+
364
+ response = post("/v1/batch", batch: requests)
365
+ responses = parse_collection(BatchEntryResponse, "batch", response)
366
+
367
+ entries = requests.zip(responses).map do |request, response|
368
+ response.request = request
369
+ response
370
+ end
371
+
372
+ result = BatchResponse.new(entries)
373
+
374
+ if result.errors?
375
+ msg = "Batch contains #{result.errors.count} errors"
376
+ raise BatchResponse::PartialSuccessError.new(msg, result)
377
+ end
378
+
379
+ result
380
+ end
381
+
311
382
  # Public: Deletes an external event from the specified calendar
312
383
  #
313
384
  # calendar_id - The String Cronofy ID for the calendar to delete the event
@@ -1231,35 +1302,6 @@ module Cronofy
1231
1302
  end
1232
1303
  end
1233
1304
 
1234
- def to_iso8601(value)
1235
- case value
1236
- when NilClass
1237
- nil
1238
- when Time
1239
- value.getutc.iso8601
1240
- else
1241
- value.iso8601
1242
- end
1243
- end
1244
-
1245
- def encode_event_time(time)
1246
- result = time
1247
-
1248
- case time
1249
- when String
1250
- time
1251
- when Hash
1252
- if time[:time]
1253
- encoded_time = encode_event_time(time[:time])
1254
- time.merge(time: encoded_time)
1255
- else
1256
- time
1257
- end
1258
- else
1259
- to_iso8601(time)
1260
- end
1261
- end
1262
-
1263
1305
  class PagedResultIterator
1264
1306
  include Enumerable
1265
1307
 
@@ -0,0 +1,31 @@
1
+ module Cronofy
2
+ module TimeEncoding
3
+ def encode_event_time(value)
4
+ case value
5
+ when String
6
+ value
7
+ when Hash
8
+ if value[:time]
9
+ encoded_time = encode_event_time(value[:time])
10
+ value.merge(time: encoded_time)
11
+ else
12
+ value
13
+ end
14
+ else
15
+ to_iso8601(value)
16
+ end
17
+ end
18
+
19
+ def to_iso8601(value)
20
+ case value
21
+ when NilClass
22
+ nil
23
+ when Time
24
+ value.getutc.iso8601
25
+ else
26
+ value.iso8601
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -193,6 +193,39 @@ module Cronofy
193
193
  class Account < CronofyMash
194
194
  end
195
195
 
196
+ BatchEntry = Struct.new(:request, :response)
197
+
198
+ class BatchEntryRequest < CronofyMash
199
+ end
200
+
201
+ class BatchEntryResponse < CronofyMash
202
+ end
203
+
204
+ class BatchResponse
205
+ class PartialSuccessError < CronofyError
206
+ attr_reader :batch_response
207
+
208
+ def initialize(message, batch_response)
209
+ super(message)
210
+ @batch_response = batch_response
211
+ end
212
+ end
213
+
214
+ attr_reader :entries
215
+
216
+ def initialize(entries)
217
+ @entries = entries
218
+ end
219
+
220
+ def errors
221
+ entries.select { |entry| (entry.status % 100) != 2 }
222
+ end
223
+
224
+ def errors?
225
+ errors.any?
226
+ end
227
+ end
228
+
196
229
  class UserInfo < CronofyMash
197
230
  end
198
231
 
@@ -1,3 +1,3 @@
1
1
  module Cronofy
2
- VERSION = "0.25.1".freeze
2
+ VERSION = "0.26.0".freeze
3
3
  end
@@ -1885,4 +1885,216 @@ describe Cronofy::Client do
1885
1885
  it_behaves_like 'a Cronofy request'
1886
1886
 
1887
1887
  end
1888
+
1889
+ describe "Batch requests" do
1890
+ context "upserting an event" do
1891
+ let(:calendar_id) { 'calendar_id_123'}
1892
+ let(:request_url) { "https://api.cronofy.com/v1/batch" }
1893
+ let(:url) { URI("https://example.com") }
1894
+ let(:method) { :post }
1895
+ let(:request_headers) { json_request_headers }
1896
+
1897
+ let(:start_datetime) { Time.utc(2014, 8, 5, 15, 30, 0) }
1898
+ let(:end_datetime) { Time.utc(2014, 8, 5, 17, 0, 0) }
1899
+ let(:encoded_start_datetime) { "2014-08-05T15:30:00Z" }
1900
+ let(:encoded_end_datetime) { "2014-08-05T17:00:00Z" }
1901
+ let(:location) { { :description => "Board room" } }
1902
+
1903
+ let(:event) do
1904
+ {
1905
+ :event_id => "qTtZdczOccgaPncGJaCiLg",
1906
+ :summary => "Board meeting",
1907
+ :description => "Discuss plans for the next quarter.",
1908
+ :start => start_datetime,
1909
+ :end => end_datetime,
1910
+ :url => url,
1911
+ :location => location,
1912
+ :reminders => [
1913
+ { :minutes => 60 },
1914
+ { :minutes => 0 },
1915
+ { :minutes => 10 },
1916
+ ],
1917
+ }
1918
+ end
1919
+
1920
+ let(:request_body) do
1921
+ {
1922
+ :batch => [
1923
+ {
1924
+ :method => "POST",
1925
+ :relative_url => "/v1/calendars/#{calendar_id}/events",
1926
+ :data => {
1927
+ :event_id => "qTtZdczOccgaPncGJaCiLg",
1928
+ :summary => "Board meeting",
1929
+ :description => "Discuss plans for the next quarter.",
1930
+ :start => encoded_start_datetime,
1931
+ :end => encoded_end_datetime,
1932
+ :url => url.to_s,
1933
+ :location => location,
1934
+ :reminders => [
1935
+ { :minutes => 60 },
1936
+ { :minutes => 0 },
1937
+ { :minutes => 10 },
1938
+ ],
1939
+ }
1940
+ }
1941
+ ]
1942
+ }
1943
+ end
1944
+
1945
+ let(:correct_response_code) { 207 }
1946
+ let(:correct_response_body) do
1947
+ {
1948
+ "batch" => [
1949
+ { "status" => 202 }
1950
+ ]
1951
+ }
1952
+ end
1953
+
1954
+ subject do
1955
+ client.batch do |batch|
1956
+ batch.upsert_event(calendar_id, event)
1957
+ end
1958
+ end
1959
+
1960
+ it_behaves_like "a Cronofy request"
1961
+ end
1962
+
1963
+ context "deleting an event" do
1964
+ let(:calendar_id) { 'calendar_id_123'}
1965
+ let(:method) { :post }
1966
+ let(:request_url) { "https://api.cronofy.com/v1/batch" }
1967
+ let(:request_headers) { json_request_headers }
1968
+
1969
+ let(:event_id) { "asd1knkjsndk123123" }
1970
+
1971
+ let(:request_body) do
1972
+ {
1973
+ :batch => [
1974
+ {
1975
+ :method => "DELETE",
1976
+ :relative_url => "/v1/calendars/#{calendar_id}/events",
1977
+ :data => {
1978
+ :event_id => event_id,
1979
+ }
1980
+ }
1981
+ ]
1982
+ }
1983
+ end
1984
+
1985
+ let(:correct_response_code) { 207 }
1986
+ let(:correct_response_body) do
1987
+ {
1988
+ "batch" => [
1989
+ { "status" => 202 }
1990
+ ]
1991
+ }
1992
+ end
1993
+
1994
+ subject do
1995
+ client.batch do |batch|
1996
+ batch.delete_event(calendar_id, event_id)
1997
+ end
1998
+ end
1999
+
2000
+ it_behaves_like "a Cronofy request"
2001
+ end
2002
+
2003
+ context "deleting an external event" do
2004
+ let(:calendar_id) { 'calendar_id_123'}
2005
+ let(:method) { :post }
2006
+ let(:request_url) { "https://api.cronofy.com/v1/batch" }
2007
+ let(:request_headers) { json_request_headers }
2008
+
2009
+ let(:event_uid) { "evt_external_12345abcde" }
2010
+
2011
+ let(:request_body) do
2012
+ {
2013
+ :batch => [
2014
+ {
2015
+ :method => "DELETE",
2016
+ :relative_url => "/v1/calendars/#{calendar_id}/events",
2017
+ :data => {
2018
+ :event_uid => event_uid,
2019
+ }
2020
+ }
2021
+ ]
2022
+ }
2023
+ end
2024
+
2025
+ let(:correct_response_code) { 207 }
2026
+ let(:correct_response_body) do
2027
+ {
2028
+ "batch" => [
2029
+ { "status" => 202 }
2030
+ ]
2031
+ }
2032
+ end
2033
+
2034
+ subject do
2035
+ client.batch do |batch|
2036
+ batch.delete_external_event(calendar_id, event_uid)
2037
+ end
2038
+ end
2039
+
2040
+ it_behaves_like "a Cronofy request"
2041
+ end
2042
+
2043
+ context "partial success" do
2044
+ let(:method) { :post }
2045
+ let(:request_url) { "https://api.cronofy.com/v1/batch" }
2046
+ let(:request_headers) { json_request_headers }
2047
+
2048
+ let(:request_body) do
2049
+ {
2050
+ :batch => [
2051
+ {
2052
+ :method => "DELETE",
2053
+ :relative_url => "/v1/calendars/cal_123_abc/events",
2054
+ :data => {
2055
+ :event_id => "123",
2056
+ }
2057
+ },
2058
+ {
2059
+ :method => "DELETE",
2060
+ :relative_url => "/v1/calendars/cal_123_def/events",
2061
+ :data => {
2062
+ :event_id => "456",
2063
+ }
2064
+ }
2065
+ ]
2066
+ }
2067
+ end
2068
+
2069
+ let(:correct_response_code) { 207 }
2070
+ let(:correct_response_body) do
2071
+ {
2072
+ "batch" => [
2073
+ { "status" => 202 },
2074
+ { "status" => 404 },
2075
+ ]
2076
+ }
2077
+ end
2078
+
2079
+ subject do
2080
+ client.batch do |batch|
2081
+ batch.delete_event("cal_123_abc", "123")
2082
+ batch.delete_event("cal_123_def", "456")
2083
+ end
2084
+ end
2085
+
2086
+ it "raises an error" do
2087
+ stub_request(method, request_url)
2088
+ .with(headers: request_headers,
2089
+ body: request_body)
2090
+ .to_return(status: correct_response_code,
2091
+ headers: correct_response_headers,
2092
+ body: correct_response_body.to_json)
2093
+
2094
+ expect { subject }.to raise_error(Cronofy::BatchResponse::PartialSuccessError) do |error|
2095
+ expect(error.batch_response.errors?).to be true
2096
+ end
2097
+ end
2098
+ end
2099
+ end
1888
2100
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cronofy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.25.1
4
+ version: 0.26.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergii Paryzhskyi
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-11-20 00:00:00.000000000 Z
12
+ date: 2017-12-05 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: oauth2
@@ -121,6 +121,7 @@ files:
121
121
  - lib/cronofy/client.rb
122
122
  - lib/cronofy/errors.rb
123
123
  - lib/cronofy/response_parser.rb
124
+ - lib/cronofy/time_encoding.rb
124
125
  - lib/cronofy/types.rb
125
126
  - lib/cronofy/version.rb
126
127
  - spec/lib/cronofy/auth_spec.rb
@@ -150,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
151
  version: '0'
151
152
  requirements: []
152
153
  rubyforge_project:
153
- rubygems_version: 2.6.12
154
+ rubygems_version: 2.6.6
154
155
  signing_key:
155
156
  specification_version: 4
156
157
  summary: Cronofy - one API for all the calendars