sendgrid-ruby 5.3.0 → 6.0.4
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 +5 -5
- data/.travis.yml +22 -20
- data/CHANGELOG.md +55 -0
- data/CODE_OF_CONDUCT.md +57 -25
- data/CONTRIBUTING.md +18 -23
- data/ISSUE_TEMPLATE.md +26 -0
- data/LICENSE.md +21 -0
- data/Makefile +7 -0
- data/PULL_REQUEST_TEMPLATE.md +31 -0
- data/README.md +26 -13
- data/Rakefile +1 -1
- data/TROUBLESHOOTING.md +22 -16
- data/UPGRADE.md +5 -0
- data/USAGE.md +1103 -1101
- data/USE_CASES.md +248 -18
- data/examples/helpers/mail/example.rb +7 -7
- data/examples/ips/ips.rb +13 -0
- data/examples/mail/mail.rb +2 -2
- data/examples/scopes/scopes.rb +49 -3
- data/examples/{whitelabel/whitelabel.rb → senderauthentication/senderauthentication.rb} +27 -27
- data/examples/suppression/suppression.rb +10 -10
- data/lib/sendgrid/client.rb +12 -9
- data/lib/sendgrid/helpers/inbound/README.md +22 -5
- data/lib/sendgrid/helpers/inbound/app.rb +13 -1
- data/lib/sendgrid/helpers/inbound/public/index.html +1 -1
- data/lib/sendgrid/helpers/inbound/sample_data/default_data.txt +2 -2
- data/lib/sendgrid/helpers/inbound/sample_data/raw_data.txt +2 -2
- data/lib/sendgrid/helpers/inbound/sample_data/raw_data_with_attachments.txt +2 -2
- data/lib/sendgrid/helpers/inbound/send.rb +2 -2
- data/lib/sendgrid/helpers/ip_management/ip_management.rb +17 -0
- data/lib/sendgrid/helpers/mail/README.md +1 -1
- data/lib/sendgrid/helpers/mail/attachment.rb +24 -1
- data/lib/sendgrid/helpers/mail/category.rb +0 -8
- data/lib/sendgrid/helpers/mail/content.rb +3 -16
- data/lib/sendgrid/helpers/mail/email.rb +3 -16
- data/lib/sendgrid/helpers/mail/mail.rb +8 -40
- data/lib/sendgrid/helpers/permissions/scope.rb +28 -0
- data/lib/sendgrid/helpers/permissions/scopes.yml +309 -0
- data/lib/sendgrid/helpers/settings/README.md +1 -1
- data/lib/sendgrid/helpers/stats/stats_response.rb +1 -1
- data/lib/sendgrid/version.rb +1 -1
- data/lib/sendgrid-ruby.rb +2 -0
- data/mail_helper_v3.md +9 -9
- data/sendgrid-ruby.gemspec +3 -3
- data/spec/sendgrid/helpers/ip_management/ip_management_spec.rb +12 -0
- data/test/sendgrid/helpers/mail/test_attachment.rb +35 -0
- data/test/sendgrid/helpers/mail/test_mail.rb +29 -21
- data/test/sendgrid/permissions/test_scopes.rb +38 -0
- data/test/sendgrid/test_sendgrid-ruby.rb +21 -13
- metadata +22 -11
- data/.github/ISSUE_TEMPLATE +0 -17
- data/.github/PULL_REQUEST_TEMPLATE +0 -24
- data/LICENSE.txt +0 -22
@@ -19,9 +19,9 @@ puts response.headers
|
|
19
19
|
# DELETE /suppression/blocks #
|
20
20
|
|
21
21
|
data = JSON.parse('{
|
22
|
-
"delete_all": false,
|
22
|
+
"delete_all": false,
|
23
23
|
"emails": [
|
24
|
-
"example1@example.com",
|
24
|
+
"example1@example.com",
|
25
25
|
"example2@example.com"
|
26
26
|
]
|
27
27
|
}')
|
@@ -65,9 +65,9 @@ puts response.headers
|
|
65
65
|
# DELETE /suppression/bounces #
|
66
66
|
|
67
67
|
data = JSON.parse('{
|
68
|
-
"delete_all": true,
|
68
|
+
"delete_all": true,
|
69
69
|
"emails": [
|
70
|
-
"example@example.com",
|
70
|
+
"example@example.com",
|
71
71
|
"example2@example.com"
|
72
72
|
]
|
73
73
|
}')
|
@@ -112,9 +112,9 @@ puts response.headers
|
|
112
112
|
# DELETE /suppression/invalid_emails #
|
113
113
|
|
114
114
|
data = JSON.parse('{
|
115
|
-
"delete_all": false,
|
115
|
+
"delete_all": false,
|
116
116
|
"emails": [
|
117
|
-
"example1@example.com",
|
117
|
+
"example1@example.com",
|
118
118
|
"example2@example.com"
|
119
119
|
]
|
120
120
|
}')
|
@@ -148,7 +148,7 @@ puts response.headers
|
|
148
148
|
# GET /suppression/spam_report/{email} #
|
149
149
|
|
150
150
|
email = "test_url_param"
|
151
|
-
response = sg.client.suppression.
|
151
|
+
response = sg.client.suppression.spam_reports._(email).get()
|
152
152
|
puts response.status_code
|
153
153
|
puts response.body
|
154
154
|
puts response.headers
|
@@ -158,7 +158,7 @@ puts response.headers
|
|
158
158
|
# DELETE /suppression/spam_report/{email} #
|
159
159
|
|
160
160
|
email = "test_url_param"
|
161
|
-
response = sg.client.suppression.
|
161
|
+
response = sg.client.suppression.spam_reports._(email).delete()
|
162
162
|
puts response.status_code
|
163
163
|
puts response.body
|
164
164
|
puts response.headers
|
@@ -178,9 +178,9 @@ puts response.headers
|
|
178
178
|
# DELETE /suppression/spam_reports #
|
179
179
|
|
180
180
|
data = JSON.parse('{
|
181
|
-
"delete_all": false,
|
181
|
+
"delete_all": false,
|
182
182
|
"emails": [
|
183
|
-
"example1@example.com",
|
183
|
+
"example1@example.com",
|
184
184
|
"example2@example.com"
|
185
185
|
]
|
186
186
|
}')
|
data/lib/sendgrid/client.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Quickly and easily access the SendGrid API.
|
1
|
+
# Quickly and easily access the Twilio SendGrid API.
|
2
2
|
require 'ruby_http_client'
|
3
3
|
require_relative 'version'
|
4
4
|
|
@@ -6,26 +6,29 @@ module SendGrid
|
|
6
6
|
# Initialize the HTTP client
|
7
7
|
class API
|
8
8
|
attr_accessor :client
|
9
|
-
attr_reader :request_headers, :host, :version
|
9
|
+
attr_reader :request_headers, :host, :version, :impersonate_subuser
|
10
10
|
# * *Args* :
|
11
|
-
# - +api_key+ -> your SendGrid API key
|
11
|
+
# - +api_key+ -> your Twilio SendGrid API key
|
12
12
|
# - +host+ -> the base URL for the API
|
13
13
|
# - +request_headers+ -> any headers that you want to be globally applied
|
14
14
|
# - +version+ -> the version of the API you wish to access,
|
15
15
|
# currently only "v3" is supported
|
16
16
|
#
|
17
|
-
def initialize(api_key: '', host: nil, request_headers: nil, version: nil)
|
18
|
-
@api_key
|
19
|
-
@host
|
20
|
-
@version
|
21
|
-
@
|
22
|
-
@
|
17
|
+
def initialize(api_key: '', host: nil, request_headers: nil, version: nil, impersonate_subuser: nil)
|
18
|
+
@api_key = api_key
|
19
|
+
@host = host ? host : 'https://api.sendgrid.com'
|
20
|
+
@version = version ? version : 'v3'
|
21
|
+
@impersonate_subuser = impersonate_subuser
|
22
|
+
@user_agent = "sendgrid/#{SendGrid::VERSION};ruby"
|
23
|
+
@request_headers = JSON.parse('
|
23
24
|
{
|
24
25
|
"Authorization": "Bearer ' + @api_key + '",
|
25
26
|
"Accept": "application/json",
|
26
27
|
"User-agent": "' + @user_agent + '"
|
27
28
|
}
|
28
29
|
')
|
30
|
+
@request_headers['On-Behalf-Of'] = @impersonate_subuser if @impersonate_subuser
|
31
|
+
|
29
32
|
|
30
33
|
@request_headers = @request_headers.merge(request_headers) if request_headers
|
31
34
|
@client = Client.new(host: "#{@host}/#{@version}",
|
@@ -2,12 +2,29 @@
|
|
2
2
|
|
3
3
|
## Table of Contents
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
- [Installation](#installation)
|
6
|
+
- [Quick Start for Local Testing with Sample Data](#quick-start-for-local-testing-with-sample-data)
|
7
|
+
- [Quick Start for Local Testing with Real Data](#quick-start-for-local-testing-with-real-data)
|
8
|
+
- [Code Walkthrough](#code-walkthrough)
|
9
|
+
- [app.rb](#apprb)
|
10
|
+
- [config.yml](#configyml)
|
11
|
+
- [send.rb & /sample_data](#sendrb--sampledata)
|
12
|
+
- [Contributing](#contributing)
|
9
13
|
|
10
14
|
<a name="quick_start_local_sample"></a>
|
15
|
+
|
16
|
+
|
17
|
+
# Installation
|
18
|
+
|
19
|
+
In addition to the installation instructions in
|
20
|
+
[the main readme](https://github.com/sendgrid/sendgrid-ruby/tree/master/#installation),
|
21
|
+
you must also add sinatra to your Gemfile:
|
22
|
+
|
23
|
+
```
|
24
|
+
gem 'sinatra', '>= 1.4.7', '< 3'
|
25
|
+
```
|
26
|
+
|
27
|
+
|
11
28
|
# Quick Start for Local Testing with Sample Data
|
12
29
|
|
13
30
|
```bash
|
@@ -53,7 +70,7 @@ In another terminal, use [ngrok](https://ngrok.com/) to allow external access to
|
|
53
70
|
ngrok http 9292
|
54
71
|
```
|
55
72
|
|
56
|
-
Update your SendGrid Incoming Parse settings: [Settings Page](https://app.sendgrid.com/settings/parse) | [Docs](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Pointing-to-a-Hostname-and-URL)
|
73
|
+
Update your Twilio SendGrid Incoming Parse settings: [Settings Page](https://app.sendgrid.com/settings/parse) | [Docs](https://sendgrid.com/docs/Classroom/Basics/Inbound_Parse_Webhook/setting_up_the_inbound_parse_webhook.html#-Pointing-to-a-Hostname-and-URL)
|
57
74
|
|
58
75
|
- For the HOSTNAME field, use the domain that you changed the MX records (e.g. inbound.yourdomain.com)
|
59
76
|
- For the URL field, use the URL generated by ngrok + /inbound, e.g http://XXXXXXX.ngrok.io/inbound
|
@@ -1,4 +1,16 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'sinatra'
|
3
|
+
rescue LoadError
|
4
|
+
puts <<-NOTE
|
5
|
+
As of sengrid verison 6, sinatra is no longer specified as a dependency of
|
6
|
+
the sendgrid gem. All the functionality of the inbound server is still the same
|
7
|
+
and fully supported, but you just need to include the sinatra dependency in your gemfile
|
8
|
+
yourself, like so:
|
9
|
+
|
10
|
+
gem 'sinatra', '>= 1.4.7', '< 3'
|
11
|
+
NOTE
|
12
|
+
raise
|
13
|
+
end
|
2
14
|
require 'logger'
|
3
15
|
require 'json'
|
4
16
|
require 'yaml'
|
@@ -20,7 +20,7 @@ inbound@inbound.example.com
|
|
20
20
|
--xYzZY
|
21
21
|
Content-Disposition: form-data; name="html"
|
22
22
|
|
23
|
-
<html><body><strong>Hello SendGrid!</body></html>
|
23
|
+
<html><body><strong>Hello Twilio SendGrid!</body></html>
|
24
24
|
|
25
25
|
--xYzZY
|
26
26
|
Content-Disposition: form-data; name="from"
|
@@ -29,7 +29,7 @@ Example User <test@example.com>
|
|
29
29
|
--xYzZY
|
30
30
|
Content-Disposition: form-data; name="text"
|
31
31
|
|
32
|
-
Hello SendGrid!
|
32
|
+
Hello Twilio SendGrid!
|
33
33
|
|
34
34
|
--xYzZY
|
35
35
|
Content-Disposition: form-data; name="sender_ip"
|
@@ -16,13 +16,13 @@ Content-Type: multipart/alternative; boundary=001a113ee97c89842f0539be8e7a
|
|
16
16
|
--001a113ee97c89842f0539be8e7a
|
17
17
|
Content-Type: text/plain; charset=UTF-8
|
18
18
|
|
19
|
-
Hello SendGrid!
|
19
|
+
Hello Twilio SendGrid!
|
20
20
|
|
21
21
|
--001a113ee97c89842f0539be8e7a
|
22
22
|
Content-Type: text/html; charset=UTF-8
|
23
23
|
Content-Transfer-Encoding: quoted-printable
|
24
24
|
|
25
|
-
<html><body><strong>Hello SendGrid!</body></html>
|
25
|
+
<html><body><strong>Hello Twilio SendGrid!</body></html>
|
26
26
|
|
27
27
|
--001a113ee97c89842f0539be8e7a--
|
28
28
|
|
@@ -19,13 +19,13 @@ Content-Type: multipart/alternative; boundary=001a1140ffb6f4fc5f053a2257e0
|
|
19
19
|
--001a1140ffb6f4fc5f053a2257e0
|
20
20
|
Content-Type: text/plain; charset=UTF-8
|
21
21
|
|
22
|
-
Hello SendGrid!
|
22
|
+
Hello Twilio SendGrid!
|
23
23
|
|
24
24
|
--001a1140ffb6f4fc5f053a2257e0
|
25
25
|
Content-Type: text/html; charset=UTF-8
|
26
26
|
Content-Transfer-Encoding: quoted-printable
|
27
27
|
|
28
|
-
<html><body><strong>Hello SendGrid!</body></html>
|
28
|
+
<html><body><strong>Hello Twilio SendGrid!</body></html>
|
29
29
|
|
30
30
|
--001a1140ffb6f4fc5f053a2257e0--
|
31
31
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
# A module for sending test SendGrid Inbound Parse messages
|
1
|
+
# A module for sending test Twilio SendGrid Inbound Parse messages
|
2
2
|
# Usage: ruby ./send.rb [path to file containing test data]
|
3
3
|
require 'ruby_http_client'
|
4
4
|
require 'yaml'
|
@@ -14,7 +14,7 @@ client = SendGrid::Client.new(host: host)
|
|
14
14
|
File.open(argv[0]) do |file|
|
15
15
|
data = file.read
|
16
16
|
headers = {
|
17
|
-
'User-Agent' => 'SendGrid-Test',
|
17
|
+
'User-Agent' => 'Twilio-SendGrid-Test',
|
18
18
|
'Content-Type' => 'multipart/form-data; boundary=xYzZY'
|
19
19
|
}
|
20
20
|
response = client.post(
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module SendGrid
|
4
|
+
class IpManagement
|
5
|
+
attr_accessor :sendgrid_client
|
6
|
+
|
7
|
+
def initialize(sendgrid_client:)
|
8
|
+
@sendgrid_client = sendgrid_client
|
9
|
+
end
|
10
|
+
|
11
|
+
def unassigned
|
12
|
+
response = @sendgrid_client.ips.get
|
13
|
+
ips = JSON.parse(response.body)
|
14
|
+
ips.select {|ip| ip.subusers.empty?}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'json'
|
2
|
+
require 'base64'
|
2
3
|
|
3
4
|
module SendGrid
|
4
5
|
class Attachment
|
@@ -11,11 +12,18 @@ module SendGrid
|
|
11
12
|
end
|
12
13
|
|
13
14
|
def content=(content)
|
15
|
+
@encoded_content = nil
|
14
16
|
@content = content
|
15
17
|
end
|
16
18
|
|
17
19
|
def content
|
18
|
-
@
|
20
|
+
return @encoded_content if @encoded_content
|
21
|
+
|
22
|
+
if @content.respond_to?(:read)
|
23
|
+
@encoded_content = encode @content
|
24
|
+
else
|
25
|
+
@encoded_content = @content
|
26
|
+
end
|
19
27
|
end
|
20
28
|
|
21
29
|
def type=(type)
|
@@ -59,5 +67,20 @@ module SendGrid
|
|
59
67
|
'content_id' => self.content_id
|
60
68
|
}.delete_if { |_, value| value.to_s.strip == '' }
|
61
69
|
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def encode(io)
|
74
|
+
str = io.read
|
75
|
+
# Since the API expects UTF-8, we need to ensure that we're
|
76
|
+
# converting other formats to it so (byte-wise) Base64 encoding
|
77
|
+
# will come through properly on the other side.
|
78
|
+
#
|
79
|
+
# Not much to be done to try to handle encoding for files opened
|
80
|
+
# in binary mode, but at least we can faithfully convey the
|
81
|
+
# bytes.
|
82
|
+
str = str.encode('UTF-8') unless io.respond_to?(:binmode?) && io.binmode?
|
83
|
+
Base64.encode64 str
|
84
|
+
end
|
62
85
|
end
|
63
86
|
end
|
@@ -2,27 +2,14 @@ require 'json'
|
|
2
2
|
|
3
3
|
module SendGrid
|
4
4
|
class Content
|
5
|
-
def initialize(type: nil, value: nil)
|
6
|
-
@type = type
|
7
|
-
@value = value
|
8
|
-
end
|
9
|
-
|
10
|
-
def type=(type)
|
11
|
-
@type = type
|
12
|
-
end
|
13
5
|
|
14
|
-
|
15
|
-
@type
|
16
|
-
end
|
6
|
+
attr_accessor :type, :value
|
17
7
|
|
18
|
-
def
|
8
|
+
def initialize(type: nil, value: nil)
|
9
|
+
@type = type
|
19
10
|
@value = value
|
20
11
|
end
|
21
12
|
|
22
|
-
def value
|
23
|
-
@value
|
24
|
-
end
|
25
|
-
|
26
13
|
def to_json(*)
|
27
14
|
{
|
28
15
|
'type' => self.type,
|
@@ -2,6 +2,9 @@ require 'json'
|
|
2
2
|
|
3
3
|
module SendGrid
|
4
4
|
class Email
|
5
|
+
|
6
|
+
attr_accessor :email, :name
|
7
|
+
|
5
8
|
def initialize(email: nil, name: nil)
|
6
9
|
if name
|
7
10
|
@email = email
|
@@ -11,22 +14,6 @@ module SendGrid
|
|
11
14
|
end
|
12
15
|
end
|
13
16
|
|
14
|
-
def email=(email)
|
15
|
-
@email = email
|
16
|
-
end
|
17
|
-
|
18
|
-
def email
|
19
|
-
@email
|
20
|
-
end
|
21
|
-
|
22
|
-
def name=(name)
|
23
|
-
@name = name
|
24
|
-
end
|
25
|
-
|
26
|
-
def name
|
27
|
-
@name
|
28
|
-
end
|
29
|
-
|
30
17
|
def split_email(email)
|
31
18
|
split = /(?:(?<address>.+)\s)?<?(?<email>.+@[^>]+)>?/.match(email)
|
32
19
|
return split[:email], split[:address]
|
@@ -5,6 +5,7 @@ require 'json'
|
|
5
5
|
module SendGrid
|
6
6
|
class Mail
|
7
7
|
|
8
|
+
attr_accessor :subject, :ip_pool_name, :template_id, :send_at, :batch_id
|
8
9
|
attr_reader :personalizations, :contents, :attachments, :categories, :sections, :headers, :custom_args
|
9
10
|
|
10
11
|
def initialize(from_email=nil, subj=nil, to_email=nil, cont=nil)
|
@@ -44,14 +45,6 @@ module SendGrid
|
|
44
45
|
@from.nil? ? nil : @from.to_json
|
45
46
|
end
|
46
47
|
|
47
|
-
def subject=(subject)
|
48
|
-
@subject = subject
|
49
|
-
end
|
50
|
-
|
51
|
-
def subject
|
52
|
-
@subject
|
53
|
-
end
|
54
|
-
|
55
48
|
def add_personalization(personalization)
|
56
49
|
@personalizations << personalization.to_json
|
57
50
|
end
|
@@ -60,6 +53,13 @@ module SendGrid
|
|
60
53
|
@contents << content.to_json
|
61
54
|
end
|
62
55
|
|
56
|
+
def check_for_secrets(patterns)
|
57
|
+
contents = @contents.map { |content| content['value'] }.join(' ')
|
58
|
+
patterns.each do |pattern|
|
59
|
+
raise SecurityError.new('Content contains sensitive information.') if contents.match(pattern)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
63
|
def add_attachment(attachment)
|
64
64
|
@attachments << attachment.to_json
|
65
65
|
end
|
@@ -68,14 +68,6 @@ module SendGrid
|
|
68
68
|
@categories << category.name
|
69
69
|
end
|
70
70
|
|
71
|
-
def template_id=(template_id)
|
72
|
-
@template_id = template_id
|
73
|
-
end
|
74
|
-
|
75
|
-
def template_id
|
76
|
-
@template_id
|
77
|
-
end
|
78
|
-
|
79
71
|
def add_section(section)
|
80
72
|
section = section.to_json
|
81
73
|
@sections = @sections.merge(section['section'])
|
@@ -91,22 +83,6 @@ module SendGrid
|
|
91
83
|
@custom_args = @custom_args.merge(custom_arg['custom_arg'])
|
92
84
|
end
|
93
85
|
|
94
|
-
def send_at=(send_at)
|
95
|
-
@send_at = send_at
|
96
|
-
end
|
97
|
-
|
98
|
-
def send_at
|
99
|
-
@send_at
|
100
|
-
end
|
101
|
-
|
102
|
-
def batch_id=(batch_id)
|
103
|
-
@batch_id = batch_id
|
104
|
-
end
|
105
|
-
|
106
|
-
def batch_id
|
107
|
-
@batch_id
|
108
|
-
end
|
109
|
-
|
110
86
|
def asm=(asm)
|
111
87
|
@asm = asm
|
112
88
|
end
|
@@ -115,14 +91,6 @@ module SendGrid
|
|
115
91
|
@asm.nil? ? nil : @asm.to_json
|
116
92
|
end
|
117
93
|
|
118
|
-
def ip_pool_name=(ip_pool_name)
|
119
|
-
@ip_pool_name = ip_pool_name
|
120
|
-
end
|
121
|
-
|
122
|
-
def ip_pool_name
|
123
|
-
@ip_pool_name
|
124
|
-
end
|
125
|
-
|
126
94
|
def mail_settings=(mail_settings)
|
127
95
|
@mail_settings = mail_settings
|
128
96
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# This is used for getting scopes
|
2
|
+
require 'yaml'
|
3
|
+
|
4
|
+
module SendGrid
|
5
|
+
class Scope
|
6
|
+
SCOPES = YAML.load_file(File.dirname(__FILE__) + '/scopes.yml').freeze
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def admin_permissions
|
10
|
+
SCOPES.values.map(&:values).flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
def read_only_permissions
|
14
|
+
SCOPES.map { |_, v| v[:read] }.flatten
|
15
|
+
end
|
16
|
+
|
17
|
+
SCOPES.each_key do |endpoint|
|
18
|
+
define_method "#{endpoint}_read_only_permissions" do
|
19
|
+
SCOPES[endpoint][:read]
|
20
|
+
end
|
21
|
+
|
22
|
+
define_method "#{endpoint}_full_access_permissions" do
|
23
|
+
SCOPES[endpoint].values.flatten
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|