postscale 1.0.0
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +224 -0
- data/lib/postscale/attachments.rb +76 -0
- data/lib/postscale/client.rb +84 -0
- data/lib/postscale/configuration.rb +40 -0
- data/lib/postscale/errors.rb +26 -0
- data/lib/postscale/http_client.rb +280 -0
- data/lib/postscale/resources/aliases.rb +27 -0
- data/lib/postscale/resources/dkim.rb +28 -0
- data/lib/postscale/resources/domains.rb +35 -0
- data/lib/postscale/resources/emails.rb +36 -0
- data/lib/postscale/resources/inbound.rb +22 -0
- data/lib/postscale/resources/resource.rb +35 -0
- data/lib/postscale/resources/stats.rb +28 -0
- data/lib/postscale/resources/suppressions.rb +36 -0
- data/lib/postscale/resources/templates.rb +31 -0
- data/lib/postscale/resources/trust.rb +15 -0
- data/lib/postscale/resources/usage.rb +11 -0
- data/lib/postscale/resources/warming.rb +33 -0
- data/lib/postscale/resources/webhooks.rb +35 -0
- data/lib/postscale/response.rb +36 -0
- data/lib/postscale/version.rb +5 -0
- data/lib/postscale/webhook_verification.rb +107 -0
- data/lib/postscale.rb +71 -0
- data/postscale.gemspec +29 -0
- metadata +75 -0
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
class HttpClient
|
|
5
|
+
IDEMPOTENT_METHODS = %w[GET HEAD OPTIONS].freeze
|
|
6
|
+
RETRYABLE_ERRORS = [
|
|
7
|
+
Net::OpenTimeout,
|
|
8
|
+
Net::ReadTimeout,
|
|
9
|
+
Errno::ECONNREFUSED,
|
|
10
|
+
Errno::ECONNRESET,
|
|
11
|
+
Errno::EHOSTUNREACH,
|
|
12
|
+
Errno::ETIMEDOUT,
|
|
13
|
+
SocketError,
|
|
14
|
+
EOFError
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
USER_AGENT = "postscale-ruby/#{Postscale::VERSION}"
|
|
18
|
+
|
|
19
|
+
def initialize(config)
|
|
20
|
+
@config = config
|
|
21
|
+
@base_uri = URI.parse(config.base_url)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Perform a GET request.
|
|
25
|
+
def get(path, params: nil, headers: nil, parse_as: :json)
|
|
26
|
+
request("GET", path, params: params, headers: headers, parse_as: parse_as)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Perform a POST request with a JSON body.
|
|
30
|
+
def post(path, json: nil, headers: nil, parse_as: :json)
|
|
31
|
+
request("POST", path, json: json, headers: headers, parse_as: parse_as)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Perform a PUT request with a JSON body.
|
|
35
|
+
def put(path, json: nil, headers: nil, parse_as: :json)
|
|
36
|
+
request("PUT", path, json: json, headers: headers, parse_as: parse_as)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Perform a PATCH request with a JSON body.
|
|
40
|
+
def patch(path, json: nil, headers: nil, parse_as: :json)
|
|
41
|
+
request("PATCH", path, json: json, headers: headers, parse_as: parse_as)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Perform a DELETE request.
|
|
45
|
+
def delete(path, params: nil, headers: nil, parse_as: :json)
|
|
46
|
+
request("DELETE", path, params: params, headers: headers, parse_as: parse_as)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def request(method, path, json: nil, params: nil, headers: nil, parse_as: :json)
|
|
50
|
+
method = method.to_s.upcase
|
|
51
|
+
attempts = max_attempts(method)
|
|
52
|
+
last_error = nil
|
|
53
|
+
|
|
54
|
+
attempts.times do |attempt|
|
|
55
|
+
uri = build_uri(path, params)
|
|
56
|
+
request = build_request(method, uri, json, headers)
|
|
57
|
+
|
|
58
|
+
begin
|
|
59
|
+
response = perform_request(uri, request)
|
|
60
|
+
rescue *RETRYABLE_ERRORS => e
|
|
61
|
+
last_error = network_error(e)
|
|
62
|
+
if retry_network_error?(method, attempt, attempts)
|
|
63
|
+
sleep_for(backoff(attempt))
|
|
64
|
+
next
|
|
65
|
+
end
|
|
66
|
+
return failure(last_error)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
response_headers = headers_from(response)
|
|
70
|
+
status = response.code.to_i
|
|
71
|
+
|
|
72
|
+
if status >= 200 && status < 300
|
|
73
|
+
return Result.new(data: parse_success(response, parse_as), error: nil, headers: response_headers)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
body = parse_error_body(response)
|
|
77
|
+
error = api_error(status, body, response_headers.request_id)
|
|
78
|
+
last_error = error
|
|
79
|
+
|
|
80
|
+
if retry_response?(method, status, attempt, attempts)
|
|
81
|
+
sleep_for(retry_delay(response, body, attempt))
|
|
82
|
+
next
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
return Result.new(data: nil, error: error, headers: response_headers)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
failure(last_error || APIError.new(message: "Postscale API request failed after all retry attempts.", code: "application_error"))
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
def build_uri(path, params = nil)
|
|
94
|
+
uri = @base_uri.dup
|
|
95
|
+
base_path = @base_uri.path.to_s.chomp("/")
|
|
96
|
+
request_path = path.to_s.start_with?("/") ? path.to_s : "/#{path}"
|
|
97
|
+
uri.path = "#{base_path}#{request_path}"
|
|
98
|
+
query = query_string(params)
|
|
99
|
+
uri.query = query unless query.nil? || query.empty?
|
|
100
|
+
uri
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def build_request(method, uri, json, headers)
|
|
104
|
+
request_class = Net::HTTP.const_get(method.capitalize)
|
|
105
|
+
request = request_class.new(uri)
|
|
106
|
+
apply_headers(request, headers)
|
|
107
|
+
|
|
108
|
+
unless json.nil?
|
|
109
|
+
request.body = JSON.generate(json)
|
|
110
|
+
request.content_type = "application/json"
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
request
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def apply_headers(request, headers)
|
|
117
|
+
@config.headers.each { |key, value| request[key.to_s] = value.to_s }
|
|
118
|
+
default_headers.each { |key, value| request[key] = value }
|
|
119
|
+
(headers || {}).each { |key, value| request[key.to_s] = value.to_s }
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def default_headers
|
|
123
|
+
{
|
|
124
|
+
"Authorization" => "Bearer #{@config.api_key}",
|
|
125
|
+
"User-Agent" => USER_AGENT,
|
|
126
|
+
"Accept" => "application/json"
|
|
127
|
+
}
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def query_string(params)
|
|
131
|
+
return nil if params.nil? || params.empty?
|
|
132
|
+
|
|
133
|
+
pairs = []
|
|
134
|
+
params.each do |key, value|
|
|
135
|
+
next if value.nil?
|
|
136
|
+
|
|
137
|
+
if value.is_a?(Array)
|
|
138
|
+
value.each { |item| pairs << [key, item] unless item.nil? }
|
|
139
|
+
else
|
|
140
|
+
pairs << [key, value]
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
URI.encode_www_form(pairs)
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
def perform_request(uri, request)
|
|
147
|
+
return @config.transport.call(uri, request) if @config.transport
|
|
148
|
+
|
|
149
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
150
|
+
http.use_ssl = (uri.scheme == "https")
|
|
151
|
+
http.open_timeout = @config.timeout
|
|
152
|
+
http.read_timeout = @config.timeout
|
|
153
|
+
http.write_timeout = @config.timeout
|
|
154
|
+
http.request(request)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def max_attempts(method)
|
|
158
|
+
return 1 unless IDEMPOTENT_METHODS.include?(method)
|
|
159
|
+
|
|
160
|
+
@config.max_retries + 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def retry_network_error?(method, attempt, attempts)
|
|
164
|
+
IDEMPOTENT_METHODS.include?(method) && attempt + 1 < attempts
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def retry_response?(method, status, attempt, attempts)
|
|
168
|
+
attempt + 1 < attempts && IDEMPOTENT_METHODS.include?(method) && (status == 429 || status >= 500)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def retry_delay(response, body, attempt)
|
|
172
|
+
retry_after = response["Retry-After"]
|
|
173
|
+
parsed = parse_retry_after(retry_after) if retry_after
|
|
174
|
+
return parsed unless parsed.nil?
|
|
175
|
+
|
|
176
|
+
if body.is_a?(Hash)
|
|
177
|
+
seconds = body["retry_after_seconds"] || body[:retry_after_seconds]
|
|
178
|
+
return seconds.to_f if seconds.is_a?(Numeric) && seconds.positive?
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
backoff(attempt)
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def parse_retry_after(value)
|
|
185
|
+
return nil if value.nil? || value.empty?
|
|
186
|
+
return value.to_f if value.match?(/\A\d+(\.\d+)?\z/) && value.to_f.positive?
|
|
187
|
+
|
|
188
|
+
parsed = Time.httpdate(value)
|
|
189
|
+
[parsed.to_f - Time.now.to_f, 0.0].max
|
|
190
|
+
rescue ArgumentError
|
|
191
|
+
nil
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
def backoff(attempt)
|
|
195
|
+
[0.25 * (2**attempt), 5.0].min
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
def sleep_for(seconds)
|
|
199
|
+
@config.sleeper.call(seconds)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def parse_success(response, parse_as)
|
|
203
|
+
body = response.body
|
|
204
|
+
return body.to_s.b if parse_as == :bytes
|
|
205
|
+
return body.to_s if parse_as == :text
|
|
206
|
+
return nil if parse_as == :void || response.code.to_i == 204
|
|
207
|
+
return nil if body.nil? || body.empty?
|
|
208
|
+
|
|
209
|
+
JSON.parse(body)
|
|
210
|
+
rescue JSON::ParserError
|
|
211
|
+
body
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def parse_error_body(response)
|
|
215
|
+
body = response.body
|
|
216
|
+
return nil if body.nil? || body.empty?
|
|
217
|
+
|
|
218
|
+
JSON.parse(body)
|
|
219
|
+
rescue JSON::ParserError
|
|
220
|
+
body
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
def headers_from(response)
|
|
224
|
+
raw = {}
|
|
225
|
+
response.each_header { |key, value| raw[key] = value }
|
|
226
|
+
Headers.new(raw)
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
def api_error(status, body, request_id)
|
|
230
|
+
code, message = parse_error_envelope(body)
|
|
231
|
+
APIError.new(
|
|
232
|
+
message: message || "Postscale API request failed with status #{status}.",
|
|
233
|
+
code: code || default_error_code(status),
|
|
234
|
+
status_code: status,
|
|
235
|
+
request_id: request_id,
|
|
236
|
+
body: body
|
|
237
|
+
)
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def parse_error_envelope(body)
|
|
241
|
+
return [nil, body] if body.is_a?(String)
|
|
242
|
+
return [nil, nil] unless body.is_a?(Hash)
|
|
243
|
+
|
|
244
|
+
error = body["error"] || body[:error]
|
|
245
|
+
if error.is_a?(Hash)
|
|
246
|
+
return [error["code"] || error[:code], error["message"] || error[:message]]
|
|
247
|
+
end
|
|
248
|
+
if error.is_a?(String)
|
|
249
|
+
message = body["message"] || body[:message] || error
|
|
250
|
+
return [error, message]
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
[body["code"] || body[:code], body["message"] || body[:message]]
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def default_error_code(status)
|
|
257
|
+
return "unauthorized" if status == 401
|
|
258
|
+
return "forbidden" if status == 403
|
|
259
|
+
return "not_found" if status == 404
|
|
260
|
+
return "conflict" if status == 409
|
|
261
|
+
return "unprocessable_entity" if status == 422
|
|
262
|
+
return "rate_limit_exceeded" if status == 429
|
|
263
|
+
return "internal_error" if status >= 500
|
|
264
|
+
|
|
265
|
+
"api_error"
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def network_error(error)
|
|
269
|
+
APIError.new(
|
|
270
|
+
message: error.message,
|
|
271
|
+
code: "application_error",
|
|
272
|
+
status_code: nil
|
|
273
|
+
)
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
def failure(error)
|
|
277
|
+
Result.new(data: nil, error: error, headers: Headers.new)
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Aliases < Resource
|
|
6
|
+
def create(request = nil, **kwargs)
|
|
7
|
+
@http.post("/v1/aliases", json: request_hash(request, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def list(params = nil, **kwargs)
|
|
11
|
+
@http.get("/v1/aliases", params: params_hash(params, kwargs))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get(id)
|
|
15
|
+
@http.get("/v1/aliases/#{encode(id)}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update(id, request = nil, **kwargs)
|
|
19
|
+
@http.patch("/v1/aliases/#{encode(id)}", json: request_hash(request, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete(id)
|
|
23
|
+
@http.delete("/v1/aliases/#{encode(id)}")
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class DKIM < Resource
|
|
6
|
+
def generate(domain_id = nil, request = nil, **kwargs)
|
|
7
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
8
|
+
@http.post("/v1/domains/#{encode(domain_id)}/dkim", json: request_hash(request, kwargs))
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def list(domain_id = nil, **kwargs)
|
|
12
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
13
|
+
@http.get("/v1/domains/#{encode(domain_id)}/dkim")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def rotate(domain_id = nil, request = nil, **kwargs)
|
|
17
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
18
|
+
@http.post("/v1/domains/#{encode(domain_id)}/dkim/rotate", json: request_hash(request, kwargs))
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def deactivate(domain_id = nil, selector = nil, **kwargs)
|
|
22
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
23
|
+
selector = identifier(:selector, selector, kwargs)
|
|
24
|
+
@http.delete("/v1/domains/#{encode(domain_id)}/dkim/#{encode(selector)}")
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Domains < Resource
|
|
6
|
+
def create(request = nil, **kwargs)
|
|
7
|
+
@http.post("/v1/domains", json: request_hash(request, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def list(params = nil, **kwargs)
|
|
11
|
+
@http.get("/v1/domains", params: params_hash(params, kwargs))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get(id)
|
|
15
|
+
@http.get("/v1/domains/#{encode(id)}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update(id, request = nil, **kwargs)
|
|
19
|
+
@http.put("/v1/domains/#{encode(id)}", json: request_hash(request, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete(id)
|
|
23
|
+
@http.delete("/v1/domains/#{encode(id)}")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def verify(id)
|
|
27
|
+
@http.post("/v1/domains/#{encode(id)}/verify")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def dns(id)
|
|
31
|
+
@http.get("/v1/domains/#{encode(id)}/dns")
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Emails < Resource
|
|
6
|
+
def send(request = nil, **kwargs)
|
|
7
|
+
body = request_hash(request, kwargs)
|
|
8
|
+
Attachments.validate(body["attachments"] || body[:attachments])
|
|
9
|
+
@http.post("/v1/send", json: body)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def send_batch(request = nil, **kwargs)
|
|
13
|
+
body = request.is_a?(Array) ? { "emails" => request } : request_hash(request, kwargs)
|
|
14
|
+
Array(body["emails"] || body[:emails]).each do |email|
|
|
15
|
+
Attachments.validate(email["attachments"] || email[:attachments])
|
|
16
|
+
end
|
|
17
|
+
@http.post("/v1/send/batch", json: body)
|
|
18
|
+
end
|
|
19
|
+
alias batch send_batch
|
|
20
|
+
|
|
21
|
+
def list(params = nil, **kwargs)
|
|
22
|
+
params = params_hash(params, kwargs)
|
|
23
|
+
@http.get("/v1/emails", params: params)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def get(id)
|
|
27
|
+
@http.get("/v1/emails/#{encode(id)}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def list_events(id)
|
|
31
|
+
@http.get("/v1/emails/#{encode(id)}/events")
|
|
32
|
+
end
|
|
33
|
+
alias events list_events
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Inbound < Resource
|
|
6
|
+
def list(params = nil, **kwargs)
|
|
7
|
+
@http.get("/v1/inbound-emails", params: params_hash(params, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def get(id)
|
|
11
|
+
@http.get("/v1/inbound-emails/#{encode(id)}")
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def download_attachment(email_id, attachment_id)
|
|
15
|
+
@http.get(
|
|
16
|
+
"/v1/inbound-emails/#{encode(email_id)}/attachments/#{encode(attachment_id)}/download",
|
|
17
|
+
parse_as: :bytes
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Resource
|
|
6
|
+
def initialize(http)
|
|
7
|
+
@http = http
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def encode(value)
|
|
13
|
+
URI.encode_www_form_component(value.to_s)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def request_hash(request = nil, kwargs = {})
|
|
17
|
+
data = {}
|
|
18
|
+
data.merge!(request) if request
|
|
19
|
+
data.merge!(kwargs) unless kwargs.empty?
|
|
20
|
+
data
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def params_hash(params = nil, kwargs = {})
|
|
24
|
+
request_hash(params, kwargs)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def identifier(name, value, kwargs = {})
|
|
28
|
+
found = value || kwargs.delete(name)
|
|
29
|
+
raise ArgumentError, "#{name} is required" if found.nil? || found.to_s.empty?
|
|
30
|
+
|
|
31
|
+
found
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Stats < Resource
|
|
6
|
+
def aggregate(domain_id = nil, params = nil, **kwargs)
|
|
7
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
8
|
+
@http.get("/v1/domains/#{encode(domain_id)}/stats", params: params_hash(params, kwargs))
|
|
9
|
+
end
|
|
10
|
+
alias get aggregate
|
|
11
|
+
|
|
12
|
+
def daily(domain_id = nil, params = nil, **kwargs)
|
|
13
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
14
|
+
@http.get("/v1/domains/#{encode(domain_id)}/stats/daily", params: params_hash(params, kwargs))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def hourly(domain_id = nil, params = nil, **kwargs)
|
|
18
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
19
|
+
@http.get("/v1/domains/#{encode(domain_id)}/stats/hourly", params: params_hash(params, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def isp(domain_id = nil, params = nil, **kwargs)
|
|
23
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
24
|
+
@http.get("/v1/domains/#{encode(domain_id)}/stats/isp", params: params_hash(params, kwargs))
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Suppressions < Resource
|
|
6
|
+
def list(params = nil, **kwargs)
|
|
7
|
+
@http.get("/v1/suppressions", params: params_hash(params, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def add(request = nil, **kwargs)
|
|
11
|
+
@http.post("/v1/suppressions", json: request_hash(request, kwargs))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def check(email = nil, **kwargs)
|
|
15
|
+
params = email.is_a?(Hash) ? params_hash(email, kwargs) : params_hash({ email: email }, kwargs)
|
|
16
|
+
@http.get("/v1/suppressions/check", params: params)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def remove(identifier)
|
|
20
|
+
@http.delete("/v1/suppressions/#{encode(identifier)}")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def import_preview(request = nil, **kwargs)
|
|
24
|
+
@http.post("/v1/imports/suppressions/preview", json: request_hash(request, kwargs))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def import_job(id)
|
|
28
|
+
@http.get("/v1/imports/suppressions/jobs/#{encode(id)}")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def commit_import(id)
|
|
32
|
+
@http.post("/v1/imports/suppressions/jobs/#{encode(id)}/commit")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Templates < Resource
|
|
6
|
+
def create(request = nil, **kwargs)
|
|
7
|
+
@http.post("/v1/templates", json: request_hash(request, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def list(params = nil, **kwargs)
|
|
11
|
+
@http.get("/v1/templates", params: params_hash(params, kwargs))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def get(id)
|
|
15
|
+
@http.get("/v1/templates/#{encode(id)}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def update(id, request = nil, **kwargs)
|
|
19
|
+
@http.put("/v1/templates/#{encode(id)}", json: request_hash(request, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def delete(id)
|
|
23
|
+
@http.delete("/v1/templates/#{encode(id)}")
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def preview(id, request = nil, **kwargs)
|
|
27
|
+
@http.post("/v1/templates/#{encode(id)}/preview", json: request_hash(request, kwargs))
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Trust < Resource
|
|
6
|
+
def get_review_request
|
|
7
|
+
@http.get("/v1/trust/review-request")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def create_review_request(request = nil, **kwargs)
|
|
11
|
+
@http.post("/v1/trust/review-request", json: request_hash(request, kwargs))
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Warming < Resource
|
|
6
|
+
def get_status(domain_id = nil, **kwargs)
|
|
7
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
8
|
+
@http.get("/v1/domains/#{encode(domain_id)}/warming")
|
|
9
|
+
end
|
|
10
|
+
alias status get_status
|
|
11
|
+
|
|
12
|
+
def history(domain_id = nil, params = nil, **kwargs)
|
|
13
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
14
|
+
@http.get("/v1/domains/#{encode(domain_id)}/warming/history", params: params_hash(params, kwargs))
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def start(domain_id = nil, request = nil, **kwargs)
|
|
18
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
19
|
+
@http.post("/v1/domains/#{encode(domain_id)}/warming/start", json: request_hash(request, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def pause(domain_id = nil, request = nil, **kwargs)
|
|
23
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
24
|
+
@http.post("/v1/domains/#{encode(domain_id)}/warming/pause", json: request_hash(request, kwargs))
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def resume(domain_id = nil, **kwargs)
|
|
28
|
+
domain_id = identifier(:domain_id, domain_id, kwargs)
|
|
29
|
+
@http.post("/v1/domains/#{encode(domain_id)}/warming/resume")
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Postscale
|
|
4
|
+
module Resources
|
|
5
|
+
class Webhooks < Resource
|
|
6
|
+
def create(request = nil, **kwargs)
|
|
7
|
+
@http.post("/v1/webhooks", json: request_hash(request, kwargs))
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def list(params = nil, **kwargs)
|
|
11
|
+
@http.get("/v1/webhooks", params: params_hash(params, kwargs))
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def delete(id)
|
|
15
|
+
@http.delete("/v1/webhooks/#{encode(id)}")
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def deliveries(params = nil, **kwargs)
|
|
19
|
+
@http.get("/v1/webhook-deliveries", params: params_hash(params, kwargs))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def endpoint_deliveries(id, params = nil, **kwargs)
|
|
23
|
+
@http.get("/v1/webhooks/#{encode(id)}/deliveries", params: params_hash(params, kwargs))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def rotate_secret(id, request = nil, **kwargs)
|
|
27
|
+
@http.post("/v1/webhooks/#{encode(id)}/rotate", json: request_hash(request, kwargs))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def verify_signature(body, signature_header, secrets, **options)
|
|
31
|
+
Webhook.verify_signature(body, signature_header, secrets, **options)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|