microsoft-graph-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 681f5c337d3be9042df1a0bc986a4dab043d9ce4710e802542f04a6f08dcf0f9
4
+ data.tar.gz: 0bfd2956c6f8cef9c213d0a6ffb5f24760ae36156491586446d1464cdb7fdd88
5
+ SHA512:
6
+ metadata.gz: d3ac2c34280ba8befb56971b92815e2373a4d9e7f76565a8b28e5c590814a587faec2abecaf41585e020a2c87b2ab30bba1058ab0ee2cff351a352d7dcc0aa9d
7
+ data.tar.gz: 3e0525b30a394e7084369ae8bfd6acd24cdbef1597c74ff80570797981bf7a42c68f494f5be4a946cb63816b7633556556d00edae5b7bab5f7b636e82fcb17de
data/.gitignore ADDED
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ /.idea/
10
+
11
+ # rspec failure tracking
12
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,39 @@
1
+ AllCops:
2
+ TargetRubyVersion: 3.0
3
+ NewCops: enable
4
+
5
+ Style/Documentation:
6
+ Enabled: false
7
+
8
+ Style/StringLiterals:
9
+ Enabled: true
10
+ EnforcedStyle: double_quotes
11
+
12
+ Style/StringLiteralsInInterpolation:
13
+ Enabled: true
14
+ EnforcedStyle: double_quotes
15
+
16
+ Style/RegexpLiteral:
17
+ EnforcedStyle: slashes
18
+
19
+ Metrics/AbcSize:
20
+ Enabled: false
21
+
22
+ Metrics/ParameterLists:
23
+ CountKeywordArgs: false
24
+
25
+ Metrics/BlockLength:
26
+ Enabled: false
27
+
28
+ Metrics/MethodLength:
29
+ Max: 30
30
+ CountAsOne: ['array', 'hash', 'heredoc']
31
+
32
+ Layout/FirstArgumentIndentation:
33
+ EnforcedStyle: consistent
34
+
35
+ Layout/FirstHashElementIndentation:
36
+ Enabled: false
37
+
38
+ Layout/LineLength:
39
+ Max: 120
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ microsoft-graph
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-3.0.1
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ language: ruby
3
+ cache: bundler
4
+ rvm:
5
+ - 3.0.1
6
+ before_install: gem install bundler -v 2.2.15
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2021-09-16
4
+ - Initial release
5
+ - Supports batched and single calls to the Graph API
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in microsoft-graph.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+ gem "rspec", "~> 3.0"
10
+ gem "httparty"
11
+ gem "rubocop", "~> 1.7"
12
+
13
+ group :test do
14
+ gem "awesome_print"
15
+ gem "vcr"
16
+ gem "webmock"
17
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,78 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ microsoft-graph-client (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ addressable (2.8.0)
10
+ public_suffix (>= 2.0.2, < 5.0)
11
+ ast (2.4.2)
12
+ awesome_print (1.9.2)
13
+ crack (0.4.5)
14
+ rexml
15
+ diff-lcs (1.4.4)
16
+ hashdiff (1.0.1)
17
+ httparty (0.19.0)
18
+ mime-types (~> 3.0)
19
+ multi_xml (>= 0.5.2)
20
+ mime-types (3.3.1)
21
+ mime-types-data (~> 3.2015)
22
+ mime-types-data (3.2021.0901)
23
+ multi_xml (0.6.0)
24
+ parallel (1.21.0)
25
+ parser (3.0.2.0)
26
+ ast (~> 2.4.1)
27
+ public_suffix (4.0.6)
28
+ rainbow (3.0.0)
29
+ rake (13.0.6)
30
+ regexp_parser (2.1.1)
31
+ rexml (3.2.5)
32
+ rspec (3.10.0)
33
+ rspec-core (~> 3.10.0)
34
+ rspec-expectations (~> 3.10.0)
35
+ rspec-mocks (~> 3.10.0)
36
+ rspec-core (3.10.1)
37
+ rspec-support (~> 3.10.0)
38
+ rspec-expectations (3.10.1)
39
+ diff-lcs (>= 1.2.0, < 2.0)
40
+ rspec-support (~> 3.10.0)
41
+ rspec-mocks (3.10.2)
42
+ diff-lcs (>= 1.2.0, < 2.0)
43
+ rspec-support (~> 3.10.0)
44
+ rspec-support (3.10.2)
45
+ rubocop (1.21.0)
46
+ parallel (~> 1.10)
47
+ parser (>= 3.0.0.0)
48
+ rainbow (>= 2.2.2, < 4.0)
49
+ regexp_parser (>= 1.8, < 3.0)
50
+ rexml
51
+ rubocop-ast (>= 1.9.1, < 2.0)
52
+ ruby-progressbar (~> 1.7)
53
+ unicode-display_width (>= 1.4.0, < 3.0)
54
+ rubocop-ast (1.11.0)
55
+ parser (>= 3.0.1.1)
56
+ ruby-progressbar (1.11.0)
57
+ unicode-display_width (2.1.0)
58
+ vcr (6.0.0)
59
+ webmock (3.14.0)
60
+ addressable (>= 2.8.0)
61
+ crack (>= 0.3.2)
62
+ hashdiff (>= 0.4.0, < 2.0.0)
63
+
64
+ PLATFORMS
65
+ x86_64-darwin-20
66
+
67
+ DEPENDENCIES
68
+ awesome_print
69
+ httparty
70
+ microsoft-graph-client!
71
+ rake (~> 13.0)
72
+ rspec (~> 3.0)
73
+ rubocop (~> 1.7)
74
+ vcr
75
+ webmock
76
+
77
+ BUNDLED WITH
78
+ 2.2.15
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Kirill Klimuk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,215 @@
1
+ # Microsoft::Graph
2
+
3
+ This is a [Microsoft Graph](https://docs.microsoft.com/en-us/graph/overview) client gem, since the official client library is [not supported](https://github.com/microsoftgraph/msgraph-sdk-ruby).
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem "microsoft-graph-client"
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle install
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install microsoft-graph
20
+
21
+ ## Usage
22
+
23
+ The gem supports both individual calls to the API. To issue either of these calls, it's important to initialize the Graph
24
+ with the access token.
25
+
26
+ To get the authentication token, it's recommended to use the [Windows Azure Active Directory Authentication Library](https://github.com/AzureAD/azure-activedirectory-library-for-ruby) (ADAL) if you're building a console app.
27
+ You will have to [register the app](https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-v2-netcore-daemon#register-and-download-the-app) and add permissions.
28
+
29
+ Here's some sample code to get you started:
30
+
31
+ ```ruby
32
+ username = 'admin@tenant.onmicrosoft.com'
33
+ password = 'xxxxxxxxxxxx'
34
+ client_id = 'xxxxx-xxxx-xxx-xxxxxx-xxxxxxx'
35
+ client_secret = 'xxxXXXxxXXXxxxXXXxxXXXXXXXXxxxxxx='
36
+ tenant = 'tenant.onmicrosoft.com'
37
+ user_cred = ADAL::UserCredential.new(username, password)
38
+ client_cred = ADAL::ClientCredential.new(client_id, client_secret)
39
+ context = ADAL::AuthenticationContext.new(ADAL::Authority::WORLD_WIDE_AUTHORITY, tenant)
40
+ resource = "https://graph.microsoft.com"
41
+ tokens = context.acquire_token_for_user(resource, client_cred, user_cred)
42
+
43
+ graph = Microsoft::Graph.new(token: tokens.access_token)
44
+ ```
45
+
46
+ ### Individual API Calls
47
+ To make individual calls, you can use the `#call` instance method on `Microsoft::Graph`:
48
+
49
+ `Microsoft::Graph#call(endpoint, method: "GET", headers: {}, params: nil, body: nil)`
50
+ - `endpoint` - the URL of the API without the version as a string. For example: `/me`.
51
+ - `method` - the preferred HTTP method as a string.
52
+ - `headers` - a hash of additional headers. `Microsoft::Graph` adds the appropriate JSON headers.
53
+ - `body` - the body, as a hash. The keys of the body will be converted from snake-case to camel-case when sent (i.e. `number_format` to `numberFormat`).
54
+
55
+ As a syntactic sugar, `Microsoft::Graph` exposes the 5 HTTP methods as instance methods:
56
+ - `GET` - `#get`
57
+ - `POST`- `#post`
58
+ - `PUT`- `#put`
59
+ - `PATCH`- `#patch`
60
+ - `DELETE`- `#delete`
61
+
62
+ There are two additional quality of life features for Ruby
63
+ - You can pass the request body's keys in snake-case.
64
+ - The response will convert the API's camel-cased response to snake-case.
65
+
66
+ Below are a couple of examples:
67
+ ```ruby
68
+ # Get a signed in user
69
+ # https://docs.microsoft.com/en-us/graph/api/user-get?view=graph-rest-1.0&tabs=http
70
+ graph.get("/me")
71
+ # alternatively
72
+ graph.call("/me", method: "GET")
73
+
74
+ # sample response - Microsoft::Graph converts the response keys to be snake-cased
75
+ # Microsoft::Graph::JSONStruct {
76
+ # "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#users/$entity",
77
+ # display_name: "Kirill Klimuk",
78
+ # surname: "Klimuk",
79
+ # given_name: "Kirill",
80
+ # id: "89d5fafe0adc70ee",
81
+ # user_principal_name: "kklimuk@gmail.com"
82
+ # }
83
+ ```
84
+
85
+ ```ruby
86
+ # update an excel worksheet
87
+ # https://docs.microsoft.com/en-us/graph/api/range-update?view=graph-rest-1.0&tabs=http
88
+ graph.patch("/me/drive/items/89D5FAFE0ADC70EA!106/workbook/worksheets/Sheet1/range(address='A56:B57')", body: {
89
+ values: [%w[Hello 100], ["1/1/2016", nil]],
90
+ formulas: [[nil, nil], [nil, "=B56*2"]],
91
+ number_format: [[nil, nil], ["m-ddd", nil]] # in the API docs, this is described as numberFormat, but Microsoft::Graph allows you to use snake-cased keys
92
+ })
93
+ # alternatively
94
+ graph.call(
95
+ "/me/drive/items/89D5FAFE0ADC70EA!106/workbook/worksheets/Sheet1/range(address='A56:B57')",
96
+ method: "PATCH",
97
+ body: {
98
+ values: [%w[Hello 100], ["1/1/2016", nil]],
99
+ formulas: [[nil, nil], [nil, "=B56*2"]],
100
+ number_format: [[nil, nil], ["m-ddd", nil]] # in the API docs, this is described as numberFormat, but Microsoft::Graph allows you to use snake-cased keys
101
+ }
102
+ )
103
+
104
+ # sample response - Microsoft::Graph converts the response keys to be snake-cased
105
+ # Microsoft::Graph::JSONStruct {
106
+ # "@odata.context": "https://graph.microsoft.com/v1.0/$metadata#workbookRange",
107
+ # "@odata.type": "#microsoft.graph.workbookRange",
108
+ # "@odata.id": "/users('kklimuk%40gmail.com')/drive/items('89D5FAFE0ADC70EA%21106')/workbook/worksheets(%27%7B84FABE00-2D27-A843-B953-03E854DFA415%7D%27)/range(address=%27A56:B57%27)",
109
+ # address: "Sheet1!A56:B57",
110
+ # address_local: "Sheet1!A56:B57",
111
+ # column_count: 2,
112
+ # cell_count: 4,
113
+ # column_hidden: false,
114
+ # row_hidden: false,
115
+ # number_format: [
116
+ # %w[General General],
117
+ # %w[m-ddd General]
118
+ # ],
119
+ # column_index: 0,
120
+ # text: [
121
+ # %w[Hello 100],
122
+ # %w[1-Fri 200]
123
+ # ],
124
+ # formulas: [
125
+ # [
126
+ # "Hello",
127
+ # 100
128
+ # ],
129
+ # [
130
+ # 42_370,
131
+ # "=B56*2"
132
+ # ]
133
+ # ],
134
+ # formulas_local: [
135
+ # [
136
+ # "Hello",
137
+ # 100
138
+ # ],
139
+ # [
140
+ # 42_370,
141
+ # "=B56*2"
142
+ # ]
143
+ # ],
144
+ # formulas_r1c1: [
145
+ # [
146
+ # "Hello",
147
+ # 100
148
+ # ],
149
+ # [
150
+ # 42_370,
151
+ # "=R[-1]C*2"
152
+ # ]
153
+ # ],
154
+ # hidden: false,
155
+ # row_count: 2,
156
+ # row_index: 55,
157
+ # value_types: [
158
+ # %w[String Double],
159
+ # %w[Double Double]
160
+ # ],
161
+ # values: [
162
+ # [
163
+ # "Hello",
164
+ # 100
165
+ # ],
166
+ # [
167
+ # 42_370,
168
+ # 200
169
+ # ]
170
+ # ]
171
+ # }
172
+ ```
173
+
174
+ If an error occurs, an error will be thrown. You can inspect the error via its `response` method.
175
+
176
+ ### Batched API Calls
177
+ Microsoft has rolled out a way to send the graph [multiple requests in one](https://docs.microsoft.com/en-us/graph/json-batching).
178
+ As a result, this client library supports it out of the box with the `#batch` instance method.
179
+
180
+ Here's an example that combines both of our individual calls into a single batched call.
181
+ ```ruby
182
+ graph.batch do |batch|
183
+ batch.add("/me", id: "abc", method: "GET")
184
+ batch.add(
185
+ "/me/drive/items/89D5FAFE0ADC70EA!106/workbook/worksheets/Sheet1/range(address='A56:B57')",
186
+ id: "def",
187
+ method: "PATCH",
188
+ body: {
189
+ values: [%w[Hello 100], ["1/1/2016", nil]],
190
+ formulas: [[nil, nil], [nil, "=B56*2"]],
191
+ number_format: [[nil, nil], ["m-ddd", nil]]
192
+ }
193
+ )
194
+ end
195
+ ```
196
+
197
+ Please note: the current maximum number of calls in a single request is 20 according to Microsoft's docs.
198
+ The `#batch` method will group requests into batches of 20 to not violate this rule.
199
+
200
+ The output of the request will be an array of `Microsoft::Graph::Batch::Result`, which have both a `request` and `result` properties.
201
+ You can find the relevant result by searching for the request `id` you have passed in.
202
+
203
+ ## Development
204
+
205
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
206
+
207
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
208
+
209
+ ## Contributing
210
+
211
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kklimuk/microsoft-graph.
212
+
213
+ ## License
214
+
215
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: %i[spec rubocop]
data/bin/console ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "bundler/setup"
5
+ require "microsoft/graph"
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require "irb"
15
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Microsoft
4
+ class Graph
5
+ class Batch
6
+ attr_reader :requests
7
+
8
+ def initialize(graph, token:, size: 20)
9
+ @graph = graph
10
+ @requests = []
11
+ @token = token
12
+ @size = size
13
+ end
14
+
15
+ def add(endpoint, id: SecureRandom.uuid, method: "GET", headers: {}, params: nil, body: nil, depends_on: nil)
16
+ @requests << Request.new(
17
+ endpoint,
18
+ id: id,
19
+ method: method,
20
+ headers: headers,
21
+ params: params,
22
+ body: body,
23
+ depends_on: depends_on
24
+ )
25
+ end
26
+
27
+ def call
28
+ @requests.each_slice(@size).flat_map do |group|
29
+ requests_by_id = group.group_by(&:id).transform_values(&:first)
30
+ group.first.depends_on = nil
31
+
32
+ response = @graph.call("/$batch", method: "POST", token: @token, body: { requests: group.map(&:to_h) })
33
+ response.responses.map do |current|
34
+ Result.new(request: requests_by_id[current.id], response: current)
35
+ end
36
+ end
37
+ end
38
+
39
+ class Request
40
+ def self.parser
41
+ @parser ||= URI::Parser.new
42
+ end
43
+
44
+ def self.body_formatter
45
+ @body_formatter ||= Microsoft::Graph::BodyFormatter.new
46
+ end
47
+
48
+ attr_reader :id, :endpoint, :method, :headers, :body
49
+ attr_accessor :depends_on
50
+
51
+ def initialize(endpoint, id:, method:, headers:, params:, body:, depends_on:)
52
+ @id = id
53
+ @endpoint = "#{self.class.parser.escape(endpoint)}#{params ? "?#{params.to_query}" : ""}"
54
+ @method = method.upcase
55
+ @headers = headers
56
+ @headers[:Accept] = "application/json" if body
57
+ @headers[:"Content-Type"] = "application/json" if body
58
+ @body = body
59
+ @depends_on = depends_on
60
+ end
61
+
62
+ def to_h
63
+ hash = {
64
+ id: @id,
65
+ url: @endpoint,
66
+ method: @method
67
+ }
68
+ hash[:headers] = @headers unless @headers.empty?
69
+ hash[:body] = self.class.body_formatter.call(@body, method: @method) if @body
70
+ hash[:dependsOn] = [@depends_on] if @depends_on
71
+
72
+ hash
73
+ end
74
+ end
75
+
76
+ class Result
77
+ attr_reader :request, :response
78
+
79
+ def initialize(request:, response:)
80
+ @request = request
81
+ @response = response
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Microsoft
4
+ class Graph
5
+ class BodyFormatter
6
+ def call(body, method:)
7
+ return nil unless Microsoft::Graph::BODY_METHODS.include?(method)
8
+ return nil unless body
9
+
10
+ body.transform_keys(&method(:camelize))
11
+ end
12
+
13
+ private
14
+
15
+ def camelize(key)
16
+ string = key.to_s
17
+ return string unless string.include?("_")
18
+
19
+ string = string.sub(/^(?:(?=\b|[A-Z_])|\w)/, &:downcase)
20
+ string.gsub(%r{(?:_|(/))([a-z\d]*)}) do
21
+ "#{Regexp.last_match(1)}#{Regexp.last_match(2).capitalize}"
22
+ end.gsub("/", "::")
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Microsoft
4
+ class Graph
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "httparty"
4
+ require "securerandom"
5
+ require_relative "graph/version"
6
+ require_relative "graph/batch"
7
+ require_relative "graph/body_formatter"
8
+
9
+ module Microsoft
10
+ class Graph
11
+ GRAPH_HOST = "https://graph.microsoft.com"
12
+ BODY_METHODS = %w[POST PUT PATCH].freeze
13
+ ALLOWED_METHODS = [*BODY_METHODS, "GET", "DELETE"].freeze
14
+
15
+ def initialize(token: nil, error_handler: method(:error_handler), version: "1.0")
16
+ @token = token
17
+ @parser = URI::Parser.new
18
+ @body_formatter = Microsoft::Graph::BodyFormatter.new
19
+ @error_handler = error_handler
20
+ @version = version
21
+ end
22
+
23
+ # stubs
24
+ def get(*); end
25
+
26
+ def post(*); end
27
+
28
+ def put(*); end
29
+
30
+ def patch(*); end
31
+
32
+ def delete(*); end
33
+
34
+ ALLOWED_METHODS.each do |method|
35
+ define_method(method.downcase) { |*args, **kwargs| call(*args, method: method, **kwargs) }
36
+ end
37
+
38
+ def call(endpoint, token: @token, method: "GET", headers: {}, params: nil, body: nil)
39
+ method = method.upcase
40
+ raise ArgumentError, "`#{method}` is not a valid HTTP method." unless ALLOWED_METHODS.include?(method)
41
+
42
+ url = URI.join(GRAPH_HOST, @parser.escape("v#{@version}/#{endpoint.gsub(%r{^/}, "")}"))
43
+ headers = headers.merge(
44
+ Authorization: "Bearer #{token}",
45
+ Accept: "application/json"
46
+ )
47
+ headers[:"Content-Type"] = "application/json" if BODY_METHODS.include?(method)
48
+
49
+ response = HTTParty.send(
50
+ method.downcase,
51
+ url,
52
+ headers: headers,
53
+ query: params,
54
+ body: @body_formatter.call(body, method: method).to_json,
55
+ parser: InstanceParser
56
+ )
57
+
58
+ case response.code
59
+ when 200...400
60
+ response.parsed_response
61
+ when 400...600
62
+ error = Error.new(
63
+ "Received status code: #{response.code}. Check the `response` attribute for more details.",
64
+ response.parsed_response,
65
+ response.code
66
+ )
67
+ @error_handler.call(error)
68
+ else
69
+ raise "Unknown status code: #{response.code}"
70
+ end
71
+ end
72
+
73
+ def batch(token: @token)
74
+ batch = Batch.new(self, token: token)
75
+ yield batch
76
+ batch.call
77
+ end
78
+
79
+ def error_handler(error)
80
+ raise error
81
+ end
82
+
83
+ class Error < StandardError
84
+ attr_reader :response
85
+
86
+ def initialize(message, response = nil, _code = nil)
87
+ @response = response
88
+ super message
89
+ end
90
+ end
91
+
92
+ class InstanceParser < HTTParty::Parser
93
+ def parse
94
+ return nil unless body
95
+
96
+ JSON.parse(body, object_class: JSONStruct)
97
+ end
98
+ end
99
+
100
+ class JSONStruct < OpenStruct
101
+ def self.format(key)
102
+ HTTParty::Response.underscore(key.to_s).to_sym
103
+ end
104
+
105
+ def initialize(hash = {})
106
+ super nil
107
+ hash.each do |key, value|
108
+ self[key] = value
109
+ end
110
+ end
111
+
112
+ def []=(key, value)
113
+ formatted_key = self.class.format(key)
114
+ super formatted_key, value
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/microsoft/graph/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "microsoft-graph-client"
7
+ spec.version = Microsoft::Graph::VERSION
8
+ spec.authors = ["Kirill Klimuk"]
9
+ spec.email = ["kklimuk@gmail.com"]
10
+
11
+ spec.summary = "Access the Microsoft Graph API."
12
+ # spec.description = "TODO: Write a longer description or delete this line."
13
+ # spec.homepage = "TODO: Put your gem's website or public repo URL here."
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
21
+ end
22
+ spec.bindir = "exe"
23
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ["lib"]
25
+
26
+ # Uncomment to register a new dependency of your gem
27
+ # spec.add_dependency "example-gem", "~> 1.0"
28
+
29
+ # For more information and examples about making a new gem, checkout our
30
+ # guide at: https://bundler.io/guides/creating_gem.html
31
+ end
metadata ADDED
@@ -0,0 +1,62 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: microsoft-graph-client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kirill Klimuk
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2021-09-21 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description:
14
+ email:
15
+ - kklimuk@gmail.com
16
+ executables: []
17
+ extensions: []
18
+ extra_rdoc_files: []
19
+ files:
20
+ - ".gitignore"
21
+ - ".rspec"
22
+ - ".rubocop.yml"
23
+ - ".ruby-gemset"
24
+ - ".ruby-version"
25
+ - ".travis.yml"
26
+ - CHANGELOG.md
27
+ - Gemfile
28
+ - Gemfile.lock
29
+ - LICENSE.txt
30
+ - README.md
31
+ - Rakefile
32
+ - bin/console
33
+ - bin/setup
34
+ - lib/microsoft/graph.rb
35
+ - lib/microsoft/graph/batch.rb
36
+ - lib/microsoft/graph/body_formatter.rb
37
+ - lib/microsoft/graph/version.rb
38
+ - microsoft-graph.gemspec
39
+ homepage:
40
+ licenses:
41
+ - MIT
42
+ metadata: {}
43
+ post_install_message:
44
+ rdoc_options: []
45
+ require_paths:
46
+ - lib
47
+ required_ruby_version: !ruby/object:Gem::Requirement
48
+ requirements:
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 2.4.0
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: '0'
57
+ requirements: []
58
+ rubygems_version: 3.2.15
59
+ signing_key:
60
+ specification_version: 4
61
+ summary: Access the Microsoft Graph API.
62
+ test_files: []