cronofy 0.25.1 → 0.26.0

Sign up to get free protection for your applications and to get access to all the features.
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