ruby-office365 0.1.6 → 0.1.8
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 +7 -1
- data/Gemfile.lock +1 -1
- data/README.md +7 -5
- data/lib/office365/models/concerns/base.rb +1 -1
- data/lib/office365/models/event.rb +1 -0
- data/lib/office365/rest/api.rb +2 -2
- 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 +1 -6
- data/lib/office365/rest/mailbox.rb +1 -6
- data/lib/office365/rest/request.rb +8 -2
- data/lib/office365/rest/token.rb +1 -1
- data/lib/office365/utils/hash.rb +14 -0
- data/lib/office365/utils/string.rb +15 -1
- data/lib/office365/utils.rb +1 -1
- data/lib/office365/version.rb +1 -1
- data/lib/office365.rb +6 -0
- metadata +3 -3
- data/lib/office365/utils/to_query.rb +0 -89
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d51b843c237dae5d0af62db257a4ae5889d03e00b62fdce26f679717139a9fe6
|
|
4
|
+
data.tar.gz: 1cdb8e3c0229f929acd5354fcea731253c7535e57fbe355cc2ee816ef54597a6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b970531fc4df3e763a6b15a997e3bf0557e3e0b08772eb1d5fe4b37d17bdde9c78d95f8bd3729b2764f0a8378aa4ccd9baa56ce7abae5f35d5e21a4259fcf1c5
|
|
7
|
+
data.tar.gz: 9ad0c123acddf7965596ccd0be7ff1a0ffb710f1f665cbda60c52a6f6d4ef94641818d0404e9bd6a9b33bb1d5d15a0e43d7c36f5c7418b2a074db01d93d43fab
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -34,4 +34,10 @@
|
|
|
34
34
|
|
|
35
35
|
- Integrate REST API to get events
|
|
36
36
|
- get events `client.events`
|
|
37
|
-
- get events data with next link `client.events({next_link: 'xxx'})`
|
|
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 (2022)
|
|
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,6 +11,11 @@ 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`.
|
data/lib/office365/rest/api.rb
CHANGED
|
@@ -4,8 +4,8 @@ require_relative "./user"
|
|
|
4
4
|
require_relative "./mailbox"
|
|
5
5
|
require_relative "./calendar"
|
|
6
6
|
require_relative "./contact"
|
|
7
|
-
require_relative "./token"
|
|
8
7
|
require_relative "./event"
|
|
8
|
+
require_relative "./token"
|
|
9
9
|
|
|
10
10
|
module Office365
|
|
11
11
|
module REST
|
|
@@ -13,9 +13,9 @@ module Office365
|
|
|
13
13
|
include Office365::REST::User
|
|
14
14
|
include Office365::REST::Mailbox
|
|
15
15
|
include Office365::REST::Calendar
|
|
16
|
+
include Office365::REST::Event
|
|
16
17
|
include Office365::REST::Contact
|
|
17
18
|
include Office365::REST::Token
|
|
18
|
-
include Office365::REST::Event
|
|
19
19
|
end
|
|
20
20
|
end
|
|
21
21
|
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.ms_hash_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
|
data/lib/office365/rest/event.rb
CHANGED
|
@@ -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 events(args = {})
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{
|
|
16
|
-
results: response["value"].map { |v| Models::Event.new(v) },
|
|
17
|
-
next_link: response["@odata.nextLink"]
|
|
18
|
-
}
|
|
13
|
+
wrap_results(args.merge(kclass: Models::Event, base_uri: "/me/events"))
|
|
19
14
|
end
|
|
20
15
|
end
|
|
21
16
|
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
|
|
@@ -34,7 +34,7 @@ module Office365
|
|
|
34
34
|
faraday.adapter Faraday.default_adapter
|
|
35
35
|
faraday.response :json
|
|
36
36
|
faraday.response :logger, ::Logger.new($stdout), bodies: true if dev_developement?
|
|
37
|
-
end.post(req_url.request_uri, args.
|
|
37
|
+
end.post(req_url.request_uri, args.ms_hash_to_query)
|
|
38
38
|
|
|
39
39
|
parse_respond(response)
|
|
40
40
|
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
|
data/lib/office365/rest/token.rb
CHANGED
|
@@ -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
|
data/lib/office365/utils.rb
CHANGED
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.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Encore Shao
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2023-02-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -135,8 +135,8 @@ files:
|
|
|
135
135
|
- lib/office365/rest/token.rb
|
|
136
136
|
- lib/office365/rest/user.rb
|
|
137
137
|
- lib/office365/utils.rb
|
|
138
|
+
- lib/office365/utils/hash.rb
|
|
138
139
|
- lib/office365/utils/string.rb
|
|
139
|
-
- lib/office365/utils/to_query.rb
|
|
140
140
|
- lib/office365/version.rb
|
|
141
141
|
- ruby-office365.gemspec
|
|
142
142
|
- sig/office365.rbs
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "cgi"
|
|
4
|
-
|
|
5
|
-
class Object
|
|
6
|
-
# Alias of <tt>to_s</tt>.
|
|
7
|
-
def to_param
|
|
8
|
-
to_s
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
# Converts an object into a string suitable for use as a URL query string,
|
|
12
|
-
# using the given <tt>key</tt> as the param name.
|
|
13
|
-
def to_query(key)
|
|
14
|
-
"#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}"
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
class NilClass
|
|
19
|
-
# Returns +self+.
|
|
20
|
-
def to_param
|
|
21
|
-
self
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
class TrueClass
|
|
26
|
-
# Returns +self+.
|
|
27
|
-
def to_param
|
|
28
|
-
self
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
class FalseClass
|
|
33
|
-
# Returns +self+.
|
|
34
|
-
def to_param
|
|
35
|
-
self
|
|
36
|
-
end
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
class Array
|
|
40
|
-
# Calls <tt>to_param</tt> on all its elements and joins the result with
|
|
41
|
-
# slashes. This is used by <tt>url_for</tt> in Action Pack.
|
|
42
|
-
def to_param
|
|
43
|
-
collect(&:to_param).join "/"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# Converts an array into a string suitable for use as a URL query string,
|
|
47
|
-
# using the given +key+ as the param name.
|
|
48
|
-
#
|
|
49
|
-
# ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding"
|
|
50
|
-
def to_query(key)
|
|
51
|
-
prefix = "#{key}[]"
|
|
52
|
-
|
|
53
|
-
if empty?
|
|
54
|
-
nil.to_query(prefix)
|
|
55
|
-
else
|
|
56
|
-
collect { |value| value.to_query(prefix) }.join "&"
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
class Hash
|
|
62
|
-
# Returns a string representation of the receiver suitable for use as a URL
|
|
63
|
-
# query string:
|
|
64
|
-
#
|
|
65
|
-
# {name: 'David', nationality: 'Danish'}.to_query
|
|
66
|
-
# # => "name=David&nationality=Danish"
|
|
67
|
-
#
|
|
68
|
-
# An optional namespace can be passed to enclose key names:
|
|
69
|
-
#
|
|
70
|
-
# {name: 'David', nationality: 'Danish'}.to_query('user')
|
|
71
|
-
# # => "user%5Bname%5D=David&user%5Bnationality%5D=Danish"
|
|
72
|
-
#
|
|
73
|
-
# The string pairs "key=value" that conform the query string
|
|
74
|
-
# are sorted lexicographically in ascending order.
|
|
75
|
-
#
|
|
76
|
-
# This method is also aliased as +to_param+.
|
|
77
|
-
def to_query(namespace = nil)
|
|
78
|
-
query = collect do |key, value|
|
|
79
|
-
unless (value.is_a?(Hash) || value.is_a?(Array)) && value.empty?
|
|
80
|
-
value.to_query(namespace ? "#{namespace}[#{key}]" : key)
|
|
81
|
-
end
|
|
82
|
-
end.compact
|
|
83
|
-
|
|
84
|
-
query.sort! unless namespace.to_s.include?("[]")
|
|
85
|
-
query.join("&")
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
alias to_param to_query
|
|
89
|
-
end
|