cronofy 0.37.2 → 0.37.5

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
  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: