ruby-office365 0.1.5 → 0.1.7
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 +4 -4
- data/.rubocop.yml +4 -1
- data/CHANGELOG.md +15 -3
- data/Gemfile.lock +1 -1
- data/README.md +55 -22
- data/lib/office365/models/concerns/base.rb +1 -1
- data/lib/office365/models/event.rb +9 -0
- data/lib/office365/models.rb +1 -0
- data/lib/office365/rest/api.rb +2 -0
- data/lib/office365/rest/calendar.rb +1 -6
- data/lib/office365/rest/concerns/base.rb +40 -10
- data/lib/office365/rest/contact.rb +1 -6
- data/lib/office365/rest/event.rb +17 -0
- data/lib/office365/rest/mailbox.rb +1 -6
- data/lib/office365/rest/request.rb +7 -1
- data/lib/office365/utils/string.rb +15 -1
- data/lib/office365/utils/to_query.rb +1 -1
- data/lib/office365/version.rb +1 -1
- data/lib/office365.rb +6 -0
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '0490fef4bbf78efa42231c69e2b12fdb9f12ec37805c5e846225568e85cb03ba'
|
4
|
+
data.tar.gz: a40082526d63f968875194b969146f787de82090207132c69b7d62c344719c6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1a5220233fdf3095a0423a0433b54007ad251cc1bd3dfea051a6c2b2ef3e83586d3142198deda976ffa3425e9c6b97723e0e78af9a564872d2c42e1a9bba7a68
|
7
|
+
data.tar.gz: 445c96c052a74d5ca866769182c98a3da62de4308f83d52db760b5d2bac1fbce3c7be02cdecdfde933ea0d0c3e1c98c264f3175bba68dfbd933c8e29b55f8d15
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -15,12 +15,12 @@
|
|
15
15
|
|
16
16
|
- Integrate REST API to get mailbox with pagination
|
17
17
|
- get mailbox data with next link `client.messages({next_link: 'xxx'})`
|
18
|
-
- get
|
18
|
+
- get calenders data with next link `client.calenders({next_link: 'xxx'})`
|
19
19
|
|
20
20
|
## [0.1.3] - (2022-10-26)
|
21
21
|
|
22
22
|
- Integrate REST API to get contacts
|
23
|
-
- get
|
23
|
+
- get contacts `client.contacts`
|
24
24
|
- get contacts data with next link `client.contacts({next_link: 'xxx'})`
|
25
25
|
|
26
26
|
## [0.1.5] - (2022-10-27)
|
@@ -28,4 +28,16 @@
|
|
28
28
|
- Generate URLs for token and able to refresh token
|
29
29
|
- get authorize URL `client.authorize_url`
|
30
30
|
- get token URL `client.token_url`
|
31
|
-
- be able to refresh token `client.refresh_token!`
|
31
|
+
- be able to refresh token `client.refresh_token!`
|
32
|
+
|
33
|
+
## [0.1.6] - (2022-11-01)
|
34
|
+
|
35
|
+
- Integrate REST API to get events
|
36
|
+
- get events `client.events`
|
37
|
+
- get events data with next link `client.events({next_link: 'xxx'})`
|
38
|
+
|
39
|
+
## [0.1.7] - (2022-11-11)
|
40
|
+
|
41
|
+
- Improve performance: supports select and sort in REST APIs
|
42
|
+
- get messages by select fields `client.messages({ select: %[id] })`
|
43
|
+
- get messages by custom order `client.messages({ order: 'id asc' })`
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,5 @@
|
|
1
|
-
# Office 365
|
2
|
-
|
3
|
-
A simple ruby library to interact with Microsoft Graph and Office 365 API.
|
4
|
-
|
5
|
-
- https://developer.microsoft.com/en-us/graph/graph-explorer
|
1
|
+
# Office 365 (2022) <img src="https://i.ibb.co/g3mpswn/microsoft-office-365-logo-2016-100727915-large.webp" align="right" width="250" height="150">
|
2
|
+
A simple ruby library to interact with Microsoft Graph **[Explorer](https://developer.microsoft.com/en-us/graph/graph-explorer)** and Office 365 API
|
6
3
|
|
7
4
|
## Installation
|
8
5
|
|
@@ -14,35 +11,57 @@ If bundler is not being used to manage dependencies, install the gem by executin
|
|
14
11
|
|
15
12
|
$ gem install ruby-office365
|
16
13
|
|
14
|
+
## Features
|
15
|
+
|
16
|
+
- Supports user's mailboxes, calendars, contacts, events
|
17
|
+
- Supports refresh token
|
18
|
+
|
17
19
|
## Configuration
|
18
20
|
|
19
21
|
You can pass configuration options as a block to `Office365::REST::Client.new`.
|
20
22
|
|
23
|
+
- tenant_id: optional, only required for refresh_token
|
24
|
+
- client_id: optional, only required for refresh_token
|
25
|
+
- client_secret: optional, only required for refresh_token
|
26
|
+
- access_token: required for fetch mailbox, calendars, contacts data
|
27
|
+
- refresh_token: optional, only required for refresh_token
|
28
|
+
- debug: optional, default false, output the request information
|
29
|
+
|
30
|
+
### Used to get data from MS Graph API
|
31
|
+
|
21
32
|
```ruby
|
22
33
|
client = Office365::REST::Client.new do |config|
|
23
|
-
config.
|
24
|
-
config.
|
25
|
-
config.client_secret = "YOUR_APP_CLIENT_SECRET"
|
26
|
-
config.redirect_uri = "YOUR_APP_REDIRECT_URL"
|
27
|
-
config.access_token = "YOUR_ACCESS_TOKEN"
|
28
|
-
config.refresh_token = "YOUR_REFRESH_TOKEN"
|
34
|
+
config.access_token = "YOUR_ACCESS_TOKEN"
|
35
|
+
config.debug = "true/false" # Optional, default to false, output the information in the request
|
29
36
|
end
|
30
37
|
```
|
31
38
|
|
32
|
-
|
39
|
+
### For refresh token
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
client = Office365::REST::Client.new do |config|
|
43
|
+
config.tenant_id = "YOUR_ORG_TENANT_ID"
|
44
|
+
config.client_id = "YOUR_APP_CLIENT_ID"
|
45
|
+
config.client_secret = "YOUR_APP_CLIENT_SECRET"
|
46
|
+
config.refresh_token = "YOUR_REFRESH_TOKEN"
|
47
|
+
config.debug = "true/false" # Optional, default to false, output the information in the request
|
48
|
+
end
|
49
|
+
```
|
50
|
+
|
51
|
+
## Usage
|
33
52
|
|
34
53
|
After configuring a `client`, you can do the following things.
|
35
54
|
|
36
|
-
**
|
55
|
+
**Response structure**
|
37
56
|
|
38
|
-
-
|
39
|
-
-
|
57
|
+
- results: wrap all data into results
|
58
|
+
- next_link: get the new link for the next page of data
|
40
59
|
|
41
|
-
**to JSON**
|
60
|
+
**A simple way to convert an office365 object to JSON**
|
42
61
|
|
43
|
-
-
|
62
|
+
- as_json: convert office365 object to JSON format
|
44
63
|
|
45
|
-
**Get
|
64
|
+
**Get my profile by access token**
|
46
65
|
|
47
66
|
```ruby
|
48
67
|
irb(main):004:0> response = client.me
|
@@ -65,7 +84,7 @@ irb(main):004:0> response.as_json
|
|
65
84
|
}
|
66
85
|
```
|
67
86
|
|
68
|
-
**Get my calendars**
|
87
|
+
**Get my calendars by access token**
|
69
88
|
|
70
89
|
```ruby
|
71
90
|
irb(main):005:0> client.calendars
|
@@ -73,7 +92,15 @@ irb(main):005:0> client.calendars[:results]
|
|
73
92
|
irb(main):005:0> client.calendars[:next_link]
|
74
93
|
```
|
75
94
|
|
76
|
-
**Get my
|
95
|
+
**Get my events by access token**
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
irb(main):005:0> client.events
|
99
|
+
irb(main):005:0> client.events[:results]
|
100
|
+
irb(main):005:0> client.events[:next_link]
|
101
|
+
```
|
102
|
+
|
103
|
+
**Get my mails by access token**
|
77
104
|
|
78
105
|
```ruby
|
79
106
|
irb(main):005:0> client.messages
|
@@ -82,7 +109,7 @@ irb(main):005:0> client.messages({ filter: "createdDateTime lt 2022-01-01" })
|
|
82
109
|
irb(main):005:0> client.messages({ filter: "createdDateTime lt 2022-01-01", next_link: 'https://....' })
|
83
110
|
```
|
84
111
|
|
85
|
-
**Get my contacts**
|
112
|
+
**Get my contacts by access token**
|
86
113
|
|
87
114
|
```ruby
|
88
115
|
irb(main):018:0> response = client.contacts
|
@@ -132,7 +159,7 @@ irb(main):018:0> response[:results][0].as_json
|
|
132
159
|
}
|
133
160
|
```
|
134
161
|
|
135
|
-
**Refresh
|
162
|
+
**Refresh access token by refresh token**
|
136
163
|
|
137
164
|
```ruby
|
138
165
|
irb(main):005:0> response = client.refresh_token!
|
@@ -144,6 +171,12 @@ irb(main):005:0> response.refresh_token
|
|
144
171
|
=> "0.ARgA7EiQdLv1qECnFqPfrznKsT9ERYaGfG9Ki5WzQtEllj8YAJk.AgABAAEAAAD--DLA3VO7QrddgJg7WevrAgDs_wQA9P-Q1ODlBsrdZi-5s2mfLtEsavBgiEhGcz1KEf26fMrGFU3LM_og5l6wjSAtQ83XHLuje0_KYGol26_LGV_uH0F1MwCFR1N3ctwg4_...."
|
145
172
|
```
|
146
173
|
|
174
|
+
## Development
|
175
|
+
|
176
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `bundle exec rspec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
177
|
+
|
178
|
+
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).
|
179
|
+
|
147
180
|
## Copyright
|
148
181
|
|
149
182
|
Copyright (c) 2022 Encore Shao. See LICENSE for details.
|
data/lib/office365/models.rb
CHANGED
data/lib/office365/rest/api.rb
CHANGED
@@ -4,6 +4,7 @@ require_relative "./user"
|
|
4
4
|
require_relative "./mailbox"
|
5
5
|
require_relative "./calendar"
|
6
6
|
require_relative "./contact"
|
7
|
+
require_relative "./event"
|
7
8
|
require_relative "./token"
|
8
9
|
|
9
10
|
module Office365
|
@@ -12,6 +13,7 @@ module Office365
|
|
12
13
|
include Office365::REST::User
|
13
14
|
include Office365::REST::Mailbox
|
14
15
|
include Office365::REST::Calendar
|
16
|
+
include Office365::REST::Event
|
15
17
|
include Office365::REST::Contact
|
16
18
|
include Office365::REST::Token
|
17
19
|
end
|
@@ -10,12 +10,7 @@ module Office365
|
|
10
10
|
# params: args => { next_link: (nil / next_page_url) }
|
11
11
|
# response { results: [], next_link: '...' }
|
12
12
|
def calendars(args = {})
|
13
|
-
|
14
|
-
|
15
|
-
{
|
16
|
-
results: response["value"].map { |v| Models::Calendar.new(v) },
|
17
|
-
next_link: response["@odata.nextLink"]
|
18
|
-
}
|
13
|
+
wrap_results(args.merge(kclass: Models::Calendar, base_uri: "/me/calendars"))
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -6,21 +6,51 @@ module Office365
|
|
6
6
|
module Base
|
7
7
|
private
|
8
8
|
|
9
|
-
def
|
10
|
-
|
9
|
+
def wrap_results(args)
|
10
|
+
kclass = args.delete(:kclass)
|
11
|
+
response = get_request(args: args)
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
{
|
14
|
+
results: response["value"].map { |v| kclass.new(v) },
|
15
|
+
next_link: response["@odata.nextLink"]
|
16
|
+
}
|
17
|
+
end
|
16
18
|
|
17
|
-
|
18
|
-
|
19
|
-
req_uri
|
20
|
-
end
|
19
|
+
def get_request(args: {})
|
20
|
+
request_uri = parse_and_build_request_url(args)
|
21
21
|
|
22
22
|
Request.new(access_token, debug: debug).get(request_uri)
|
23
23
|
end
|
24
|
+
|
25
|
+
# https://learn.microsoft.com/en-us/graph/query-parameters?view=graph-rest-1.0
|
26
|
+
# OData system query options
|
27
|
+
# Click the examples to try them in [Graph Explorer](https://developer.microsoft.com/zh-cn/graph/graph-explorer)
|
28
|
+
|
29
|
+
# $count Retrieves the total count of matching resources. /me/messages?$top=2&$count=true
|
30
|
+
# $expand Retrieves related resources. /groups?$expand=members
|
31
|
+
# $filter Filters results (rows). /users?$filter=startswith(givenName,'J')
|
32
|
+
# $format Returns the results in the specified media format. /users?$format=json
|
33
|
+
# $orderby Orders results. /users?$orderby=displayName desc
|
34
|
+
# $search Returns results based on search criteria. /me/messages?$search=pizza
|
35
|
+
# $select Filters properties (columns). /users?$select=givenName,surname
|
36
|
+
# $skip Indexes into a result set.
|
37
|
+
# Also used by some APIs to implement paging and can be used together with $top to manually page results. /me/messages?$skip=11
|
38
|
+
# $top Sets the page size of results. /users?$top=2
|
39
|
+
def parse_and_build_request_url(args)
|
40
|
+
next_link = args.delete(:next_link)
|
41
|
+
return next_link unless next_link.nil?
|
42
|
+
|
43
|
+
# organize params
|
44
|
+
base_uri = args.delete(:base_uri)
|
45
|
+
select_fields = args.delete(:select)
|
46
|
+
order_by = args.delete(:order)
|
47
|
+
args[:select] = select_fields.map(&:rails_camelize).join(",") if select_fields.is_a?(Array)
|
48
|
+
args[:orderby] = order_by if order_by
|
49
|
+
|
50
|
+
request_uri = ["/", Office365::API_VERSION, base_uri].join
|
51
|
+
request_uri += ["?", args.to_query].join if args.any?
|
52
|
+
request_uri
|
53
|
+
end
|
24
54
|
end
|
25
55
|
end
|
26
56
|
end
|
@@ -10,12 +10,7 @@ module Office365
|
|
10
10
|
# params: args => { next_link: (nil / next_page_url) }
|
11
11
|
# response { results: [], next_link: '...' }
|
12
12
|
def contacts(args = {})
|
13
|
-
|
14
|
-
|
15
|
-
{
|
16
|
-
results: response["value"].map { |v| Models::Contact.new(v) },
|
17
|
-
next_link: response["@odata.nextLink"]
|
18
|
-
}
|
13
|
+
wrap_results(args.merge(kclass: Models::Contact, base_uri: "/me/contacts"))
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./concerns/base"
|
4
|
+
|
5
|
+
module Office365
|
6
|
+
module REST
|
7
|
+
module Event
|
8
|
+
include Concerns::Base
|
9
|
+
|
10
|
+
# params: args => { next_link: (nil / next_page_url) }
|
11
|
+
# response { results: [], next_link: '...' }
|
12
|
+
def events(args = {})
|
13
|
+
wrap_results(args.merge(kclass: Models::Event, base_uri: "/me/events"))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -10,12 +10,7 @@ module Office365
|
|
10
10
|
# params: args => { next_link: (nil / next_page_url) }
|
11
11
|
# response { results: [], next_link: '...' }
|
12
12
|
def messages(args = {})
|
13
|
-
|
14
|
-
|
15
|
-
{
|
16
|
-
results: response["value"].map { |v| Models::Mailbox.new(v) },
|
17
|
-
next_link: response["@odata.nextLink"]
|
18
|
-
}
|
13
|
+
wrap_results(args.merge(kclass: Models::Mailbox, base_uri: "/me/messages"))
|
19
14
|
end
|
20
15
|
end
|
21
16
|
end
|
@@ -45,8 +45,14 @@ module Office365
|
|
45
45
|
resp_body = response.body
|
46
46
|
|
47
47
|
return resp_body if response.status == 200
|
48
|
-
|
48
|
+
|
49
49
|
raise InvaliRequestError, resp_body["error_description"] if response.status == 400
|
50
|
+
raise InvalidAuthenticationTokenError, resp_body.dig("error", "message") if response.status == 401
|
51
|
+
raise AccessDeniedError, resp_body.dig("error", "message") if response.status == 403
|
52
|
+
raise NotFoundError, resp_body.dig("error", "message") if response.status == 404
|
53
|
+
raise ThrottlingError, resp_body.dig("error", "message") if response.status == 429
|
54
|
+
|
55
|
+
raise ServiceUnavailableError, resp_body.dig("error", "message") if response.status == 503
|
50
56
|
|
51
57
|
raise Error, resp_body["error"]
|
52
58
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
class String
|
4
|
-
def
|
4
|
+
def rails_underscore
|
5
5
|
gsub(/::/, "/")
|
6
6
|
.gsub(/@/, "")
|
7
7
|
.gsub(/\./, "_")
|
@@ -10,4 +10,18 @@ class String
|
|
10
10
|
.tr("-", "_")
|
11
11
|
.downcase
|
12
12
|
end
|
13
|
+
|
14
|
+
# rubocop:disable Style/SymbolProc
|
15
|
+
def rails_camelize(uppercase_first_letter: false)
|
16
|
+
string = self
|
17
|
+
return string if string !~ /_/ && string =~ /[A-Z]+.*/
|
18
|
+
|
19
|
+
string = if uppercase_first_letter
|
20
|
+
string.sub(/^[a-z\d]*/) { |match| match.capitalize }
|
21
|
+
else
|
22
|
+
string.sub(/^(?:(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
|
23
|
+
end
|
24
|
+
string.gsub(%r{(?:_|(/))([a-z\d]*)}) { "#{::Regexp.last_match(1)}#{::Regexp.last_match(2).capitalize}" }.gsub("/", "::")
|
25
|
+
end
|
26
|
+
# rubocop:enable Style/SymbolProc
|
13
27
|
end
|
@@ -11,7 +11,7 @@ class Object
|
|
11
11
|
# Converts an object into a string suitable for use as a URL query string,
|
12
12
|
# using the given <tt>key</tt> as the param name.
|
13
13
|
def to_query(key)
|
14
|
-
"
|
14
|
+
"$#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
data/lib/office365/version.rb
CHANGED
data/lib/office365.rb
CHANGED
@@ -12,6 +12,12 @@ module Office365
|
|
12
12
|
class InvalidAuthenticationTokenError < StandardError; end
|
13
13
|
class InvaliRequestError < StandardError; end
|
14
14
|
|
15
|
+
# Handling expected errors -> https://learn.microsoft.com/en-us/graph/best-practices-concept#handling-expected-errors
|
16
|
+
class AccessDeniedError < StandardError; end
|
17
|
+
class NotFoundError < StandardError; end
|
18
|
+
class ThrottlingError < StandardError; end
|
19
|
+
class ServiceUnavailableError < StandardError; end
|
20
|
+
|
15
21
|
API_HOST = "https://graph.microsoft.com"
|
16
22
|
API_VERSION = "v1.0"
|
17
23
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby-office365
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Encore Shao
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-11-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- lib/office365/models/contact.rb
|
120
120
|
- lib/office365/models/directory.rb
|
121
121
|
- lib/office365/models/email_address.rb
|
122
|
+
- lib/office365/models/event.rb
|
122
123
|
- lib/office365/models/mailbox.rb
|
123
124
|
- lib/office365/models/owner.rb
|
124
125
|
- lib/office365/models/user.rb
|
@@ -128,6 +129,7 @@ files:
|
|
128
129
|
- lib/office365/rest/client.rb
|
129
130
|
- lib/office365/rest/concerns/base.rb
|
130
131
|
- lib/office365/rest/contact.rb
|
132
|
+
- lib/office365/rest/event.rb
|
131
133
|
- lib/office365/rest/mailbox.rb
|
132
134
|
- lib/office365/rest/request.rb
|
133
135
|
- lib/office365/rest/token.rb
|
@@ -161,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
161
163
|
- !ruby/object:Gem::Version
|
162
164
|
version: '0'
|
163
165
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
166
|
+
rubygems_version: 3.2.3
|
165
167
|
signing_key:
|
166
168
|
specification_version: 4
|
167
169
|
summary: A simple ruby library to interact with Microsoft Graph and Office 365 API.
|