cronofy 0.37.2 → 0.37.5

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
  SHA256:
3
- metadata.gz: 3e09c2030d7992753a4e8f0e52af1d00d2ab6ced77f5e5b81336cb97a5c98ec6
4
- data.tar.gz: 464b7a63bdfb341f67da6f4556e4ee66b36db144d9d41270c9204ee6a10ca56c
3
+ metadata.gz: e21c23685801f569da765f2572e20cb66870a8eb2615628279bc6ff7cdcd49d9
4
+ data.tar.gz: 3c595df2b4fb1cf29c6bf76e31865a30cd7f09aaa12bcd80c485d8e3edc8c3e7
5
5
  SHA512:
6
- metadata.gz: f6a6f59a184da190d6905b495a0c067437ab422561ccf26f23e1e7d6f48fd0a0d2c63bb033d46f760b9ce24e958539a58e319b8a160c2fc2a719f4f1e3f31bcd
7
- data.tar.gz: a777db3452a6cc462ba526447c17fe0790d73dd8b08517d62363ac3f5d9b7cb076d2b77ef614ed51f981941451362bd0f568fab4749c08bdc9bc38533974729b
6
+ metadata.gz: 151382f0d9c593b19637dd8d6c452c61dceab8e4345a361def1aee2e934545a6fc97ea73dd10ece22fb83073b1670e724bcfa32a6a712112f1c2f115010a5809
7
+ data.tar.gz: 95391561459fba368ef63ff522288ce50fdb08ae90c6205c825ae781495cbdb515d7ae6d9d0814080674c2fe608cb77ad306409bf28f1b62f686eb79dc5a7ca1
data/CHANGELOG.md CHANGED
@@ -1,14 +1,26 @@
1
+ ## [0.37.5]
2
+
3
+ * Support `query_periods` as well as the original `available_periods` for Real-Time Scheduling and Real-Time Sequencing [#99]
4
+
5
+ ## [0.37.4]
6
+
7
+ * Support client_secret only clients being able to authorize `#availability` calls. [#97]
8
+
9
+ ## [0.37.3]
10
+
11
+ * Support `hmac_valid` as well as the original `hmac_match` for Client to verify a HMAC from a push notification using the client's secret.[#95]
12
+
1
13
  ## [0.37.2]
2
14
 
3
- * Support `query_periods` as well as the original `available_periods` for Availability Query and Sequenced Availability [#91]
15
+ * Support `query_periods` as well as the original `available_periods` for Availability Query and Sequenced Availability [#91]
4
16
 
5
17
  ## [0.37.1]
6
18
 
7
- * Rename `data_centre` to `data_centre` (with aliases for backwards compatibility) [#90]
19
+ * Rename `data_centre` to `data_centre` (with aliases for backwards compatibility) [#90]
8
20
 
9
21
  ## [0.37.0]
10
22
 
11
- * Add `revoke_by_token` and `revoke_by_sub` to the Client [#86]
23
+ * Add `revoke_by_token` and `revoke_by_sub` to the Client [#86]
12
24
 
13
25
  ## [0.36.1]
14
26
 
@@ -187,6 +199,9 @@
187
199
  [0.37.0]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.0
188
200
  [0.37.1]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.1
189
201
  [0.37.2]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.2
202
+ [0.37.3]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.3
203
+ [0.37.4]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.4
204
+ [0.37.5]: https://github.com/cronofy/cronofy-ruby/releases/tag/v0.37.5
190
205
 
191
206
  [#13]: https://github.com/cronofy/cronofy-ruby/pull/13
192
207
  [#16]: https://github.com/cronofy/cronofy-ruby/pull/16
@@ -231,3 +246,6 @@
231
246
  [#86]: https://github.com/cronofy/cronofy-ruby/pull/86
232
247
  [#90]: https://github.com/cronofy/cronofy-ruby/pull/90
233
248
  [#91]: https://github.com/cronofy/cronofy-ruby/pull/91
249
+ [#95]: https://github.com/cronofy/cronofy-ruby/pull/95
250
+ [#97]: https://github.com/cronofy/cronofy-ruby/pull/97
251
+ [#99]: https://github.com/cronofy/cronofy-ruby/pull/99
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Cronofy
2
2
 
3
- [![Build Status](https://travis-ci.org/cronofy/cronofy-ruby.svg?branch=master)](https://travis-ci.org/cronofy/cronofy-ruby)
3
+ [![ruby CI](https://github.com/cronofy/cronofy-ruby/actions/workflows/ci.yml/badge.svg)](https://github.com/cronofy/cronofy-ruby/actions/workflows/ci.yml)
4
4
  [![Gem Version](https://badge.fury.io/rb/cronofy.svg)](http://badge.fury.io/rb/cronofy)
5
5
 
6
6
  [Cronofy](https://www.cronofy.com) - the scheduling platform for business
@@ -134,6 +134,15 @@ To delete an event from user's calendar:
134
134
  cronofy.delete_event(calendar_id, 'uniq-id')
135
135
  ```
136
136
 
137
+ ## A feature I want is not in the SDK, how do I get it?
138
+
139
+ We add features to this SDK as they are requested, to focus on developing the Cronofy API.
140
+
141
+ If you're comfortable contributing support for an endpoint or attribute, then we love to receive pull requests!
142
+ Please create a PR mentioning the feature/API endpoint you’ve added and we’ll review it as soon as we can.
143
+
144
+ If you would like to request a feature is added by our team then please let us know by getting in touch via [support@cronofy.com](mailto:support@cronofy.com).
145
+
137
146
  ## Links
138
147
 
139
148
  * [API documentation](https://www.cronofy.com/developers/api)
@@ -471,24 +471,33 @@ module Cronofy
471
471
  parse_json(Channel, "channel", response)
472
472
  end
473
473
 
474
+ # DEPRECATED: Please use hmac_valid instead.
475
+ def hmac_match?(args)
476
+ warn "[DEPRECATION] `hmac_match?` is deprecated. Please use `hmac_valid?` instead."
477
+ hmac_valid?(args)
478
+ end
479
+
474
480
  # Public: Verifies a HMAC from a push notification using the client secret.
475
481
  #
476
482
  # args - A Hash containing the details of the push notification:
477
483
  # :body - A String of the body of the notification.
478
- # :hmac - A String of the HMAC of the notification taken from the
484
+ # :hmac - A String containing comma-separated values describing HMACs of the notification taken from the
479
485
  # Cronofy-HMAC-SHA256 header.
480
486
  #
481
- # Returns true if the HMAC provided matches the one calculated using the
487
+ # Returns true if one of the HMAC provided matches the one calculated using the
482
488
  # client secret, otherwise false.
483
- def hmac_match?(args)
489
+ def hmac_valid?(args)
484
490
  body = args[:body]
485
491
  hmac = args[:hmac]
486
492
 
493
+ return false if hmac.nil? || hmac.empty?
494
+
487
495
  sha256 = OpenSSL::Digest.new('sha256')
488
496
  digest = OpenSSL::HMAC.digest(sha256, @client_secret, body)
489
497
  calculated = Base64.encode64(digest).strip
490
498
 
491
- calculated == hmac
499
+ hmac_list = hmac.split(',')
500
+ hmac_list.include?(calculated)
492
501
  end
493
502
 
494
503
  # Public: Lists all the notification channels for the account.
@@ -835,7 +844,7 @@ module Cronofy
835
844
 
836
845
  translate_available_periods(options[:query_periods] || options[:available_periods])
837
846
 
838
- response = post("/v1/availability", options)
847
+ response = availability_post("/v1/availability", options)
839
848
 
840
849
  parse_collections(
841
850
  response,
@@ -880,7 +889,7 @@ module Cronofy
880
889
 
881
890
  translate_available_periods(options[:query_periods] || options[:available_periods])
882
891
 
883
- response = post("/v1/sequenced_availability", options)
892
+ response = availability_post("/v1/sequenced_availability", options)
884
893
  parse_collection(Sequence, "sequences", response)
885
894
  end
886
895
 
@@ -1024,7 +1033,7 @@ module Cronofy
1024
1033
  # call
1025
1034
  # :required_duration - A hash stating the length of time the event will
1026
1035
  # last for
1027
- # :available_periods - A hash stating the available periods for the event
1036
+ # :query_periods - A hash stating the available periods for the event
1028
1037
  # :start_interval - An Integer representing the start interval
1029
1038
  # of minutes for the availability query.
1030
1039
  # :buffer - An Hash containing the buffer to apply to
@@ -1060,7 +1069,7 @@ module Cronofy
1060
1069
  # }
1061
1070
  # ],
1062
1071
  # required_duration: { minutes: 60 },
1063
- # available_periods: [{
1072
+ # query_periods: [{
1064
1073
  # start: Time.utc(2017, 1, 1, 9, 00),
1065
1074
  # end: Time.utc(2017, 1, 1, 17, 00),
1066
1075
  # }]
@@ -1101,7 +1110,7 @@ module Cronofy
1101
1110
  end
1102
1111
  end
1103
1112
 
1104
- translate_available_periods(availability[:available_periods])
1113
+ translate_available_periods(availability[:query_periods] || availability[:available_periods])
1105
1114
  body[:availability] = availability
1106
1115
 
1107
1116
  response = raw_post("/v1/real_time_scheduling", body)
@@ -1167,7 +1176,7 @@ module Cronofy
1167
1176
  # an array of invitees to invite to or reject from
1168
1177
  # the event. Invitees are represented by a hash of
1169
1178
  # :email and :display_name (optional).
1170
- # :available_periods - A hash stating the available periods for the event
1179
+ # :query_periods - A hash stating the query periods for the event
1171
1180
  # target_calendars - An array of hashes stating into which calendars to insert the created
1172
1181
  # event
1173
1182
  # Raises Cronofy::CredentialsMissingError if no credentials available.
@@ -1185,7 +1194,8 @@ module Cronofy
1185
1194
 
1186
1195
  if availability = args[:availability]
1187
1196
  availability[:sequence] = map_availability_sequence(availability[:sequence])
1188
- translate_available_periods(availability[:available_periods]) if availability[:available_periods]
1197
+ periods = availability[:query_periods] || availability[:available_periods]
1198
+ translate_available_periods(periods) if periods
1189
1199
  end
1190
1200
 
1191
1201
  body[:availability] = availability
@@ -1739,8 +1749,10 @@ module Cronofy
1739
1749
  hash[:required_duration] = map_availability_required_duration(value)
1740
1750
  end
1741
1751
 
1742
- if sequence_item[:available_periods]
1743
- translate_available_periods(sequence_item[:available_periods])
1752
+ periods = sequence_item[:query_periods] || sequence_item[:available_periods]
1753
+
1754
+ if periods
1755
+ translate_available_periods(periods)
1744
1756
  end
1745
1757
 
1746
1758
  if value = sequence_item[:start_interval]
@@ -1802,6 +1814,17 @@ module Cronofy
1802
1814
  wrapped_request { @auth.api_client.request(:post, url, json_request_args(body)) }
1803
1815
  end
1804
1816
 
1817
+ # Availability Query could originally be authenticated via an access_token
1818
+ # Whilst it should be authed via an API key now, we try access_token first
1819
+ # for backward compatibility
1820
+ def availability_post(url, body)
1821
+ if @auth.access_token
1822
+ post(url, body)
1823
+ else
1824
+ wrapped_request { api_key!.post(url, json_request_args(body)) }
1825
+ end
1826
+ end
1827
+
1805
1828
  def wrapped_request
1806
1829
  yield
1807
1830
  rescue OAuth2::Error => e
@@ -1,3 +1,3 @@
1
1
  module Cronofy
2
- VERSION = "0.37.2".freeze
2
+ VERSION = "0.37.5".freeze
3
3
  end
@@ -1257,6 +1257,17 @@ describe Cronofy::Client do
1257
1257
  let(:request_url) { 'https://api.cronofy.com/v1/availability' }
1258
1258
  let(:request_headers) { json_request_headers }
1259
1259
 
1260
+ let(:client_id) { 'example_id' }
1261
+ let(:client_secret) { 'example_secret' }
1262
+ let(:token) { client_secret }
1263
+
1264
+ let(:client) do
1265
+ Cronofy::Client.new(
1266
+ client_id: client_id,
1267
+ client_secret: client_secret,
1268
+ )
1269
+ end
1270
+
1260
1271
  let(:request_body) do
1261
1272
  {
1262
1273
  "participants" => [
@@ -1770,6 +1781,87 @@ describe Cronofy::Client do
1770
1781
  it_behaves_like 'a Cronofy request'
1771
1782
  it_behaves_like 'a Cronofy request with mapped return value'
1772
1783
  end
1784
+
1785
+ context "when trying to auth with only an access_token, as originally implemented" do
1786
+ let(:access_token) { "access_token_123"}
1787
+ let(:client) { Cronofy::Client.new(access_token: access_token) }
1788
+ let(:request_headers) do
1789
+ {
1790
+ "Authorization" => "Bearer #{access_token}",
1791
+ "User-Agent" => "Cronofy Ruby #{::Cronofy::VERSION}",
1792
+ "Content-Type" => "application/json; charset=utf-8",
1793
+ }
1794
+ end
1795
+
1796
+ let(:participants) do
1797
+ { members: %w{acc_567236000909002 acc_678347111010113} }
1798
+ end
1799
+
1800
+ let(:required_duration) { 60 }
1801
+
1802
+ let(:available_periods) do
1803
+ [
1804
+ { start: Time.parse("2017-01-03T09:00:00Z"), end: Time.parse("2017-01-03T18:00:00Z") },
1805
+ { start: Time.parse("2017-01-04T09:00:00Z"), end: Time.parse("2017-01-04T18:00:00Z") },
1806
+ ]
1807
+ end
1808
+
1809
+ it_behaves_like 'a Cronofy request'
1810
+ it_behaves_like 'a Cronofy request with mapped return value'
1811
+ end
1812
+
1813
+ context "when trying to auth with both a client_secret and access_token" do
1814
+ let(:access_token) { "access_token_123" }
1815
+ let(:client_secret) { "client_secret_456" }
1816
+ let(:client) { Cronofy::Client.new(access_token: access_token, client_secret: client_secret) }
1817
+ let(:request_headers) do
1818
+ {
1819
+ "Authorization" => "Bearer #{access_token}",
1820
+ "User-Agent" => "Cronofy Ruby #{::Cronofy::VERSION}",
1821
+ "Content-Type" => "application/json; charset=utf-8",
1822
+ }
1823
+ end
1824
+
1825
+ let(:participants) do
1826
+ { members: %w{acc_567236000909002 acc_678347111010113} }
1827
+ end
1828
+
1829
+ let(:required_duration) { 60 }
1830
+
1831
+ let(:available_periods) do
1832
+ [
1833
+ { start: Time.parse("2017-01-03T09:00:00Z"), end: Time.parse("2017-01-03T18:00:00Z") },
1834
+ { start: Time.parse("2017-01-04T09:00:00Z"), end: Time.parse("2017-01-04T18:00:00Z") },
1835
+ ]
1836
+ end
1837
+
1838
+ describe "it prefers the access_token for backward compatibility" do
1839
+ it_behaves_like 'a Cronofy request'
1840
+ it_behaves_like 'a Cronofy request with mapped return value'
1841
+ end
1842
+ end
1843
+
1844
+ context "when trying to auth without a client_secret or access_token" do
1845
+ let(:client) { Cronofy::Client.new }
1846
+
1847
+ let(:participants) do
1848
+ { members: %w{acc_567236000909002 acc_678347111010113} }
1849
+ end
1850
+
1851
+ let(:required_duration) { 60 }
1852
+
1853
+ let(:available_periods) do
1854
+ [
1855
+ { start: Time.parse("2017-01-03T09:00:00Z"), end: Time.parse("2017-01-03T18:00:00Z") },
1856
+ { start: Time.parse("2017-01-04T09:00:00Z"), end: Time.parse("2017-01-04T18:00:00Z") },
1857
+ ]
1858
+ end
1859
+
1860
+
1861
+ it "raises an API Key error" do
1862
+ expect{ subject }.to raise_error(Cronofy::CredentialsMissingError)
1863
+ end
1864
+ end
1773
1865
  end
1774
1866
  end
1775
1867
 
@@ -1779,6 +1871,17 @@ describe Cronofy::Client do
1779
1871
  let(:request_url) { 'https://api.cronofy.com/v1/sequenced_availability' }
1780
1872
  let(:request_headers) { json_request_headers }
1781
1873
 
1874
+ let(:client_id) { 'example_id' }
1875
+ let(:client_secret) { 'example_secret' }
1876
+ let(:token) { client_secret }
1877
+
1878
+ let(:client) do
1879
+ Cronofy::Client.new(
1880
+ client_id: client_id,
1881
+ client_secret: client_secret,
1882
+ )
1883
+ end
1884
+
1782
1885
  let(:request_body) do
1783
1886
  {
1784
1887
  "sequence" => [
@@ -1937,6 +2040,45 @@ describe Cronofy::Client do
1937
2040
  it_behaves_like 'a Cronofy request'
1938
2041
  it_behaves_like 'a Cronofy request with mapped return value'
1939
2042
  end
2043
+
2044
+ context "when trying to auth with access_token only" do
2045
+ let(:access_token) { "access_token_123"}
2046
+ let(:client) { Cronofy::Client.new(access_token: access_token) }
2047
+ let(:request_headers) do
2048
+ {
2049
+ "Authorization" => "Bearer #{access_token}",
2050
+ "User-Agent" => "Cronofy Ruby #{::Cronofy::VERSION}",
2051
+ "Content-Type" => "application/json; charset=utf-8",
2052
+ }
2053
+ end
2054
+
2055
+ it_behaves_like 'a Cronofy request'
2056
+ it_behaves_like 'a Cronofy request with mapped return value'
2057
+ end
2058
+
2059
+ context "when trying to auth with both access_token and client_secret provided" do
2060
+ let(:client_id) { 'example_id' }
2061
+ let(:client_secret) { 'example_secret' }
2062
+ let(:access_token) { "access_token_123"}
2063
+
2064
+ let(:client) do
2065
+ Cronofy::Client.new(
2066
+ client_id: client_id,
2067
+ client_secret: client_secret,
2068
+ access_token: access_token,
2069
+ )
2070
+ end
2071
+ let(:request_headers) do
2072
+ {
2073
+ "Authorization" => "Bearer #{access_token}",
2074
+ "User-Agent" => "Cronofy Ruby #{::Cronofy::VERSION}",
2075
+ "Content-Type" => "application/json; charset=utf-8",
2076
+ }
2077
+ end
2078
+
2079
+ it_behaves_like 'a Cronofy request'
2080
+ it_behaves_like 'a Cronofy request with mapped return value'
2081
+ end
1940
2082
  end
1941
2083
  end
1942
2084
 
@@ -2199,6 +2341,14 @@ describe Cronofy::Client do
2199
2341
  it_behaves_like 'a Cronofy request'
2200
2342
  end
2201
2343
 
2344
+ context 'when passing query periods' do
2345
+ it_behaves_like 'a Cronofy request'
2346
+
2347
+ before do
2348
+ availability[:query_periods] = availability.delete(:available_periods)
2349
+ mapped_availability[:query_periods] = mapped_availability.delete(:available_periods)
2350
+ end
2351
+ end
2202
2352
  end
2203
2353
 
2204
2354
  describe "Real time sequencing" do
@@ -2387,6 +2537,21 @@ describe Cronofy::Client do
2387
2537
  it_behaves_like 'a Cronofy request'
2388
2538
  end
2389
2539
 
2540
+ context 'when passing query periods' do
2541
+ it_behaves_like 'a Cronofy request'
2542
+
2543
+ before do
2544
+ availability[:query_periods] = availability.delete(:available_periods)
2545
+ availability[:sequence].each do |sequence|
2546
+ sequence[:query_periods] = sequence.delete(:available_periods)
2547
+ end
2548
+
2549
+ mapped_availability[:query_periods] = mapped_availability.delete(:available_periods)
2550
+ mapped_availability[:sequence].each do |sequence|
2551
+ sequence[:query_periods] = sequence.delete(:available_periods)
2552
+ end
2553
+ end
2554
+ end
2390
2555
  end
2391
2556
 
2392
2557
  describe "specifying data_centre" do
@@ -2481,11 +2646,27 @@ describe Cronofy::Client do
2481
2646
  let(:body) { "{\"example\":\"well-known\"}" }
2482
2647
 
2483
2648
  it "verifies the correct HMAC" do
2484
- expect(client.hmac_match?(body: body, hmac: "6r2/HjBkqymGegX0wOfifieeUXbbHwtV/LohHS+jv6c=")).to be true
2649
+ expect(client.hmac_valid?(body: body, hmac: "6r2/HjBkqymGegX0wOfifieeUXbbHwtV/LohHS+jv6c=")).to be true
2485
2650
  end
2486
2651
 
2487
2652
  it "rejects an incorrect HMAC" do
2488
- expect(client.hmac_match?(body: body, hmac: "something-else")).to be false
2653
+ expect(client.hmac_valid?(body: body, hmac: "something-else")).to be false
2654
+ end
2655
+
2656
+ it "verifies the correct HMAC when one of the multiple HMACs splitted by ',' match" do
2657
+ expect(client.hmac_valid?(body: body, hmac: "6r2/HjBkqymGegX0wOfifieeUXbbHwtV/LohHS+jv6c=,something-else")).to be true
2658
+ end
2659
+
2660
+ it "rejects incorrect when multiple HMACs splitted by ',' don't match" do
2661
+ expect(client.hmac_valid?(body: body, hmac: "something-else,something-else2")).to be false
2662
+ end
2663
+
2664
+ it "rejects if empty HMAC" do
2665
+ expect(client.hmac_valid?(body: body, hmac: "")).to be false
2666
+ end
2667
+
2668
+ it "rejects if nil HMAC" do
2669
+ expect(client.hmac_valid?(body: body, hmac: nil)).to be false
2489
2670
  end
2490
2671
  end
2491
2672
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cronofy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.37.2
4
+ version: 0.37.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergii Paryzhskyi
8
8
  - Garry Shutler
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-01-15 00:00:00.000000000 Z
12
+ date: 2022-03-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: hashie
@@ -141,7 +141,7 @@ homepage: https://github.com/cronofy/cronofy-ruby
141
141
  licenses:
142
142
  - MIT
143
143
  metadata: {}
144
- post_install_message:
144
+ post_install_message:
145
145
  rdoc_options: []
146
146
  require_paths:
147
147
  - lib
@@ -156,8 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
156
  - !ruby/object:Gem::Version
157
157
  version: '0'
158
158
  requirements: []
159
- rubygems_version: 3.2.4
160
- signing_key:
159
+ rubygems_version: 3.2.33
160
+ signing_key:
161
161
  specification_version: 4
162
162
  summary: Cronofy - the scheduling platform for business
163
163
  test_files: