kit-rb 0.1.0 → 0.3.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 +4 -4
- data/.githooks/pre-commit +21 -0
- data/.githooks/pre-push +6 -0
- data/CHANGELOG.md +83 -0
- data/README.md +58 -16
- data/docs/DESIGN.md +38 -14
- data/docs/TASKS.md +47 -0
- data/lib/kit/auth/api_key.rb +7 -0
- data/lib/kit/auth/credential.rb +22 -0
- data/lib/kit/auth/oauth.rb +7 -8
- data/lib/kit/connection.rb +53 -20
- data/lib/kit/errors.rb +52 -15
- data/lib/kit/oauth/token.rb +9 -0
- data/lib/kit/objects/account.rb +44 -3
- data/lib/kit/objects/broadcast_click.rb +17 -0
- data/lib/kit/objects/broadcast_stats.rb +30 -0
- data/lib/kit/objects/bulk_result.rb +39 -0
- data/lib/kit/objects/custom_field.rb +4 -2
- data/lib/kit/objects/email_stats.rb +25 -0
- data/lib/kit/objects/growth_stats.rb +20 -0
- data/lib/kit/objects/post.rb +4 -2
- data/lib/kit/objects/sequence_email.rb +5 -2
- data/lib/kit/objects/subscriber.rb +16 -9
- data/lib/kit/objects/subscriber_stats.rb +26 -0
- data/lib/kit/objects/tag.rb +5 -3
- data/lib/kit/objects/webhook_endpoint.rb +7 -2
- data/lib/kit/pagination.rb +47 -3
- data/lib/kit/resources/account.rb +9 -8
- data/lib/kit/resources/base.rb +46 -4
- data/lib/kit/resources/broadcasts.rb +39 -16
- data/lib/kit/resources/bulk.rb +18 -20
- data/lib/kit/resources/custom_fields.rb +2 -2
- data/lib/kit/resources/forms.rb +3 -3
- data/lib/kit/resources/posts.rb +1 -1
- data/lib/kit/resources/purchases.rb +10 -6
- data/lib/kit/resources/sequences.rb +49 -25
- data/lib/kit/resources/snippets.rb +13 -8
- data/lib/kit/resources/subscribers.rb +24 -11
- data/lib/kit/resources/tags.rb +6 -6
- data/lib/kit/resources/webhook_endpoints.rb +12 -4
- data/lib/kit/resources/webhooks.rb +1 -1
- data/lib/kit/version.rb +1 -1
- data/lib/kit/webhooks/delivery.rb +61 -0
- data/lib/kit/webhooks/events.rb +113 -0
- data/lib/kit/webhooks/signature.rb +100 -0
- data/lib/kit-rb.rb +10 -1
- data/sig/kit-rb.rbs +240 -37
- metadata +16 -2
- data/lib/kit/objects/raw.rb +0 -12
data/lib/kit/resources/base.rb
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "erb"
|
|
4
|
+
|
|
3
5
|
module Kit
|
|
4
6
|
module Resources
|
|
5
7
|
# Shared base for every resource group. Holds the connection and exposes
|
|
6
8
|
# verb helpers under `http_*` names so a resource can define public methods
|
|
7
9
|
# like `get(id)` or `list` without colliding with the transport helpers.
|
|
8
10
|
class Base
|
|
11
|
+
# Default for optional body keywords: "not given", as distinct from nil,
|
|
12
|
+
# which Kit accepts on some fields to clear them (e.g. send_days: nil).
|
|
13
|
+
OMIT = Object.new.freeze
|
|
14
|
+
|
|
9
15
|
def initialize(connection)
|
|
10
16
|
@connection = connection
|
|
11
17
|
end
|
|
12
18
|
|
|
13
19
|
private
|
|
14
20
|
|
|
21
|
+
# Drops the keywords the caller did not pass, keeping explicit nils.
|
|
22
|
+
def given(**attributes)
|
|
23
|
+
attributes.reject { |_, value| value.equal?(OMIT) }
|
|
24
|
+
end
|
|
25
|
+
|
|
15
26
|
# Non-enveloped read (whole body) and list reads go through http_get;
|
|
16
27
|
# deletes return no object and go through http_delete. Enveloped
|
|
17
28
|
# single-object and list responses are built by `one` and `collection`.
|
|
@@ -35,13 +46,23 @@ module Kit
|
|
|
35
46
|
@connection.request(:delete, path, params: params, body: body)
|
|
36
47
|
end
|
|
37
48
|
|
|
49
|
+
# Renders an id into a path segment. Kit ids are integers; a String is
|
|
50
|
+
# accepted but percent-encoded so a value like "1/unsubscribe" cannot
|
|
51
|
+
# rewrite the route, and nil/blank raises before any request is made
|
|
52
|
+
# (a blank id would silently hit the parent list endpoint).
|
|
53
|
+
def path_id(value)
|
|
54
|
+
raise ArgumentError, "id must not be nil or blank" if value.nil? || value.to_s.strip.empty?
|
|
55
|
+
|
|
56
|
+
ERB::Util.url_encode(value.to_s)
|
|
57
|
+
end
|
|
58
|
+
|
|
38
59
|
# Sends one request that returns a single wrapped object and builds it.
|
|
39
60
|
# `key` is the envelope key (e.g. "subscriber"), `klass` the object built
|
|
40
61
|
# via `klass.from`. Centralised so a resource never hand-writes the read/
|
|
41
62
|
# build/return plumbing — it declares only verb, path, key, class, body.
|
|
42
63
|
def one(verb, path, key, klass, body: nil, params: {})
|
|
43
64
|
response = @connection.request(verb, path, params: params, body: body)
|
|
44
|
-
klass.from(response
|
|
65
|
+
klass.from(extract(response, key))
|
|
45
66
|
end
|
|
46
67
|
|
|
47
68
|
# Fetches a cursor-paginated list and wraps it in a Collection whose next
|
|
@@ -53,9 +74,30 @@ module Kit
|
|
|
53
74
|
# endpoints pass verb: :post with a filter body, still paging by cursor.
|
|
54
75
|
def collection(path, key, klass, params, verb: :get, body: nil)
|
|
55
76
|
response = @connection.request(verb, path, params: params, body: body)
|
|
56
|
-
data = response
|
|
57
|
-
Collection.new(data: data, pagination: Pagination.from(response
|
|
58
|
-
collection(path, key, klass,
|
|
77
|
+
data = extract(response, key).map { |element| klass.from(element) }
|
|
78
|
+
Collection.new(data: data, pagination: Pagination.from(extract(response, "pagination"))) do |after|
|
|
79
|
+
collection(path, key, klass, Collection.next_page_params(params, after), verb: verb, body: body)
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Reads `key` from a 2xx body, raising UnexpectedResponseError (a
|
|
84
|
+
# Kit::Error, so `rescue Kit::Error` still catches it) instead of the bare
|
|
85
|
+
# KeyError/NoMethodError a drifted or non-JSON response would otherwise
|
|
86
|
+
# produce deep inside the resource.
|
|
87
|
+
def extract(response, key)
|
|
88
|
+
return response.fetch(key) if response.is_a?(Hash) && response.key?(key)
|
|
89
|
+
|
|
90
|
+
raise UnexpectedResponseError.new(
|
|
91
|
+
"expected a JSON object with #{key.inspect} in the response, got #{describe(response)}",
|
|
92
|
+
body: response
|
|
93
|
+
)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def describe(response)
|
|
97
|
+
case response
|
|
98
|
+
when Hash then "keys #{response.keys.inspect}"
|
|
99
|
+
when nil then "an empty body"
|
|
100
|
+
else "a #{response.class} body"
|
|
59
101
|
end
|
|
60
102
|
end
|
|
61
103
|
end
|
|
@@ -12,40 +12,63 @@ module Kit
|
|
|
12
12
|
|
|
13
13
|
# GET /v4/broadcasts/:id
|
|
14
14
|
def get(id)
|
|
15
|
-
one(:get, "/v4/broadcasts/#{id}", "broadcast", Objects::Broadcast)
|
|
15
|
+
one(:get, "/v4/broadcasts/#{path_id(id)}", "broadcast", Objects::Broadcast)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
BROADCAST_FIELDS = %i[
|
|
19
|
+
subject preview_text content description public published_at send_at
|
|
20
|
+
email_address email_template_id thumbnail_alt thumbnail_url subscriber_filter
|
|
21
|
+
].freeze
|
|
22
|
+
|
|
23
|
+
# POST /v4/broadcasts. `subscriber_filter` is an array of one group
|
|
24
|
+
# ({ all: | any: | none: [{ type: "segment"|"tag", ids: [...] }] }); omit
|
|
25
|
+
# it to send to every subscriber. Timestamps are ISO 8601 (UTC assumed).
|
|
26
|
+
def create(subject: OMIT, preview_text: OMIT, content: OMIT, description: OMIT, public: OMIT,
|
|
27
|
+
published_at: OMIT, send_at: OMIT, email_address: OMIT, email_template_id: OMIT,
|
|
28
|
+
thumbnail_alt: OMIT, thumbnail_url: OMIT, subscriber_filter: OMIT)
|
|
29
|
+
body = given(subject: subject, preview_text: preview_text, content: content, description: description,
|
|
30
|
+
public: public, published_at: published_at, send_at: send_at, email_address: email_address,
|
|
31
|
+
email_template_id: email_template_id, thumbnail_alt: thumbnail_alt,
|
|
32
|
+
thumbnail_url: thumbnail_url, subscriber_filter: subscriber_filter)
|
|
33
|
+
one(:post, "/v4/broadcasts", "broadcast", Objects::Broadcast, body: body)
|
|
21
34
|
end
|
|
22
35
|
|
|
23
|
-
# PUT /v4/broadcasts/:id
|
|
24
|
-
def update(id,
|
|
25
|
-
|
|
36
|
+
# PUT /v4/broadcasts/:id — same fields as #create; only those passed change.
|
|
37
|
+
def update(id, subject: OMIT, preview_text: OMIT, content: OMIT, description: OMIT, public: OMIT,
|
|
38
|
+
published_at: OMIT, send_at: OMIT, email_address: OMIT, email_template_id: OMIT,
|
|
39
|
+
thumbnail_alt: OMIT, thumbnail_url: OMIT, subscriber_filter: OMIT)
|
|
40
|
+
body = given(subject: subject, preview_text: preview_text, content: content, description: description,
|
|
41
|
+
public: public, published_at: published_at, send_at: send_at, email_address: email_address,
|
|
42
|
+
email_template_id: email_template_id, thumbnail_alt: thumbnail_alt,
|
|
43
|
+
thumbnail_url: thumbnail_url, subscriber_filter: subscriber_filter)
|
|
44
|
+
one(:put, "/v4/broadcasts/#{path_id(id)}", "broadcast", Objects::Broadcast, body: body)
|
|
26
45
|
end
|
|
27
46
|
|
|
28
47
|
# DELETE /v4/broadcasts/:id
|
|
29
48
|
def delete(id)
|
|
30
|
-
http_delete("/v4/broadcasts/#{id}")
|
|
49
|
+
http_delete("/v4/broadcasts/#{path_id(id)}")
|
|
31
50
|
nil
|
|
32
51
|
end
|
|
33
52
|
|
|
34
|
-
# GET /v4/broadcasts/stats — a cursor-paginated list of per-broadcast stats
|
|
35
|
-
# ({ "id", "stats", "subject", "send_at" } hashes), not full broadcasts.
|
|
53
|
+
# GET /v4/broadcasts/stats — a cursor-paginated list of per-broadcast stats.
|
|
36
54
|
def stats_list(**params)
|
|
37
|
-
collection("/v4/broadcasts/stats", "broadcasts", Objects::
|
|
55
|
+
collection("/v4/broadcasts/stats", "broadcasts", Objects::BroadcastStats, params)
|
|
38
56
|
end
|
|
39
57
|
|
|
40
|
-
# GET /v4/broadcasts/:id/stats —
|
|
58
|
+
# GET /v4/broadcasts/:id/stats — one broadcast's performance stats.
|
|
41
59
|
def stats(id)
|
|
42
|
-
|
|
60
|
+
one(:get, "/v4/broadcasts/#{path_id(id)}/stats", "broadcast", Objects::BroadcastStats)
|
|
43
61
|
end
|
|
44
62
|
|
|
45
|
-
# GET /v4/broadcasts/:id/clicks —
|
|
46
|
-
#
|
|
63
|
+
# GET /v4/broadcasts/:id/clicks — a cursor-paginated Collection of the
|
|
64
|
+
# broadcast's clicked links. The API nests the array under "broadcast", so
|
|
65
|
+
# this is built directly rather than through Base#collection.
|
|
47
66
|
def clicks(id, **params)
|
|
48
|
-
http_get("/v4/broadcasts/#{id}/clicks", params: params)
|
|
67
|
+
body = http_get("/v4/broadcasts/#{path_id(id)}/clicks", params: params)
|
|
68
|
+
rows = extract(extract(body, "broadcast"), "clicks").map { |row| Objects::BroadcastClick.from(row) }
|
|
69
|
+
Collection.new(data: rows, pagination: Pagination.from(extract(body, "pagination"))) do |after|
|
|
70
|
+
clicks(id, **Collection.next_page_params(params, after))
|
|
71
|
+
end
|
|
49
72
|
end
|
|
50
73
|
end
|
|
51
74
|
end
|
data/lib/kit/resources/bulk.rb
CHANGED
|
@@ -3,60 +3,58 @@
|
|
|
3
3
|
module Kit
|
|
4
4
|
module Resources
|
|
5
5
|
# The /v4/bulk endpoints — batch operations that all require OAuth. Each call
|
|
6
|
-
# takes an array of items and an optional callback_url
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
6
|
+
# takes an array of items and an optional callback_url and returns a
|
|
7
|
+
# BulkResult: the affected records under `items`, the rejected inputs under
|
|
8
|
+
# `failures`, and `async?` when Kit queued the batch (202) and will report
|
|
9
|
+
# the outcome to callback_url instead.
|
|
10
10
|
class Bulk < Base
|
|
11
11
|
# POST /v4/bulk/subscribers
|
|
12
12
|
def create_subscribers(subscribers, callback_url: nil)
|
|
13
|
-
post
|
|
13
|
+
bulk(:post, "/v4/bulk/subscribers", "subscribers", subscribers: subscribers, callback_url: callback_url)
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
# POST /v4/bulk/custom_fields
|
|
17
17
|
def create_custom_fields(custom_fields, callback_url: nil)
|
|
18
|
-
post
|
|
18
|
+
bulk(:post, "/v4/bulk/custom_fields", "custom_fields",
|
|
19
|
+
custom_fields: custom_fields, callback_url: callback_url)
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
# POST /v4/bulk/custom_fields/subscribers
|
|
22
23
|
def update_custom_field_values(custom_field_values, callback_url: nil)
|
|
23
|
-
post
|
|
24
|
+
bulk(:post, "/v4/bulk/custom_fields/subscribers", "custom_field_values",
|
|
24
25
|
custom_field_values: custom_field_values, callback_url: callback_url)
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
# POST /v4/bulk/forms/subscribers
|
|
28
29
|
def add_subscribers_to_forms(additions, callback_url: nil)
|
|
29
|
-
post
|
|
30
|
+
bulk(:post, "/v4/bulk/forms/subscribers", "subscribers", additions: additions, callback_url: callback_url)
|
|
30
31
|
end
|
|
31
32
|
|
|
32
33
|
# POST /v4/bulk/tags
|
|
33
34
|
def create_tags(tags, callback_url: nil)
|
|
34
|
-
post
|
|
35
|
+
bulk(:post, "/v4/bulk/tags", "tags", tags: tags, callback_url: callback_url)
|
|
35
36
|
end
|
|
36
37
|
|
|
37
|
-
# DELETE /v4/bulk/tags
|
|
38
|
+
# DELETE /v4/bulk/tags — returns failures only.
|
|
38
39
|
def delete_tags(tags, callback_url: nil)
|
|
39
|
-
delete
|
|
40
|
+
bulk(:delete, "/v4/bulk/tags", nil, tags: tags, callback_url: callback_url)
|
|
40
41
|
end
|
|
41
42
|
|
|
42
43
|
# POST /v4/bulk/tags/subscribers
|
|
43
44
|
def tag_subscribers(taggings, callback_url: nil)
|
|
44
|
-
post
|
|
45
|
+
bulk(:post, "/v4/bulk/tags/subscribers", "subscribers", taggings: taggings, callback_url: callback_url)
|
|
45
46
|
end
|
|
46
47
|
|
|
47
|
-
# DELETE /v4/bulk/tags/subscribers
|
|
48
|
+
# DELETE /v4/bulk/tags/subscribers — returns failures only.
|
|
48
49
|
def remove_tag_subscribers(taggings, callback_url: nil)
|
|
49
|
-
delete
|
|
50
|
+
bulk(:delete, "/v4/bulk/tags/subscribers", nil, taggings: taggings, callback_url: callback_url)
|
|
50
51
|
end
|
|
51
52
|
|
|
52
53
|
private
|
|
53
54
|
|
|
54
|
-
def
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def delete(path, **body)
|
|
59
|
-
http_delete(path, body: body.compact)
|
|
55
|
+
def bulk(verb, path, key, **body)
|
|
56
|
+
status, response = @connection.request_with_status(verb, path, body: body.compact)
|
|
57
|
+
Objects::BulkResult.from(status, response, key)
|
|
60
58
|
end
|
|
61
59
|
end
|
|
62
60
|
end
|
|
@@ -16,12 +16,12 @@ module Kit
|
|
|
16
16
|
|
|
17
17
|
# PUT /v4/custom_fields/:id
|
|
18
18
|
def update(id, label:)
|
|
19
|
-
one(:put, "/v4/custom_fields/#{id}", "custom_field", Objects::CustomField, body: { label: label })
|
|
19
|
+
one(:put, "/v4/custom_fields/#{path_id(id)}", "custom_field", Objects::CustomField, body: { label: label })
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# DELETE /v4/custom_fields/:id
|
|
23
23
|
def delete(id)
|
|
24
|
-
http_delete("/v4/custom_fields/#{id}")
|
|
24
|
+
http_delete("/v4/custom_fields/#{path_id(id)}")
|
|
25
25
|
nil
|
|
26
26
|
end
|
|
27
27
|
end
|
data/lib/kit/resources/forms.rb
CHANGED
|
@@ -12,18 +12,18 @@ module Kit
|
|
|
12
12
|
|
|
13
13
|
# GET /v4/forms/:form_id/subscribers
|
|
14
14
|
def subscribers(form_id, **params)
|
|
15
|
-
collection("/v4/forms/#{form_id}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
15
|
+
collection("/v4/forms/#{path_id(form_id)}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
# POST /v4/forms/:form_id/subscribers/:subscriber_id
|
|
19
19
|
def add_subscriber(form_id, subscriber_id, referrer: nil)
|
|
20
|
-
one(:post, "/v4/forms/#{form_id}/subscribers/#{subscriber_id}", "subscriber",
|
|
20
|
+
one(:post, "/v4/forms/#{path_id(form_id)}/subscribers/#{path_id(subscriber_id)}", "subscriber",
|
|
21
21
|
Objects::Subscriber, body: { referrer: referrer }.compact)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
# POST /v4/forms/:form_id/subscribers
|
|
25
25
|
def add_subscriber_by_email(form_id, email_address:, referrer: nil)
|
|
26
|
-
one(:post, "/v4/forms/#{form_id}/subscribers", "subscriber", Objects::Subscriber,
|
|
26
|
+
one(:post, "/v4/forms/#{path_id(form_id)}/subscribers", "subscriber", Objects::Subscriber,
|
|
27
27
|
body: { email_address: email_address, referrer: referrer }.compact)
|
|
28
28
|
end
|
|
29
29
|
end
|
data/lib/kit/resources/posts.rb
CHANGED
|
@@ -12,14 +12,18 @@ module Kit
|
|
|
12
12
|
|
|
13
13
|
# GET /v4/purchases/:id
|
|
14
14
|
def get(id)
|
|
15
|
-
one(:get, "/v4/purchases/#{id}", "purchase", Objects::Purchase)
|
|
15
|
+
one(:get, "/v4/purchases/#{path_id(id)}", "purchase", Objects::Purchase)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
# POST /v4/purchases — the request wraps the fields under a "purchase"
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
def create(
|
|
22
|
-
|
|
18
|
+
# POST /v4/purchases — the request wraps the fields under a "purchase"
|
|
19
|
+
# key. The spec marks every field required; `products` is an array of
|
|
20
|
+
# { name, pid, lid, quantity, unit_price, sku }.
|
|
21
|
+
def create(email_address:, transaction_id:, status:, currency:, transaction_time: OMIT, subtotal: OMIT,
|
|
22
|
+
tax: OMIT, shipping: OMIT, discount: OMIT, total: OMIT, products: OMIT)
|
|
23
|
+
purchase = given(email_address: email_address, transaction_id: transaction_id, status: status,
|
|
24
|
+
currency: currency, transaction_time: transaction_time, subtotal: subtotal, tax: tax,
|
|
25
|
+
shipping: shipping, discount: discount, total: total, products: products)
|
|
26
|
+
one(:post, "/v4/purchases", "purchase", Objects::Purchase, body: { purchase: purchase })
|
|
23
27
|
end
|
|
24
28
|
end
|
|
25
29
|
end
|
|
@@ -10,67 +10,91 @@ module Kit
|
|
|
10
10
|
collection("/v4/sequences", "sequences", Objects::Sequence, params)
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
# GET /v4/sequences/:id
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
# GET /v4/sequences/:id — pass include: "stats" to embed the sequence's
|
|
14
|
+
# performance stats.
|
|
15
|
+
def get(id, include: nil)
|
|
16
|
+
one(:get, "/v4/sequences/#{path_id(id)}", "sequence", Objects::Sequence, params: { include: include }.compact)
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
# GET /v4/sequences/:sequence_id/subscribers
|
|
19
20
|
def subscribers(sequence_id, **params)
|
|
20
|
-
collection("/v4/sequences/#{sequence_id}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
21
|
+
collection("/v4/sequences/#{path_id(sequence_id)}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
# POST /v4/sequences
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
# POST /v4/sequences. `send_days` is an array of weekday names,
|
|
25
|
+
# `send_hour` 0–23, `time_zone` an IANA name; `exclude_subscriber_sources`
|
|
26
|
+
# is [{ type: "tag"|"sequence"|"form"|"segment", ids: [...] }].
|
|
27
|
+
def create(name:, email_address: OMIT, email_template_id: OMIT, send_days: OMIT, send_hour: OMIT,
|
|
28
|
+
time_zone: OMIT, active: OMIT, repeat: OMIT, hold: OMIT, exclude_subscriber_sources: OMIT)
|
|
29
|
+
body = given(name: name, email_address: email_address, email_template_id: email_template_id,
|
|
30
|
+
send_days: send_days, send_hour: send_hour, time_zone: time_zone, active: active,
|
|
31
|
+
repeat: repeat, hold: hold, exclude_subscriber_sources: exclude_subscriber_sources)
|
|
32
|
+
one(:post, "/v4/sequences", "sequence", Objects::Sequence, body: body)
|
|
26
33
|
end
|
|
27
34
|
|
|
28
|
-
# PUT /v4/sequences/:id
|
|
29
|
-
def update(id,
|
|
30
|
-
|
|
35
|
+
# PUT /v4/sequences/:id — same fields as #create; only those passed change.
|
|
36
|
+
def update(id, name: OMIT, email_address: OMIT, email_template_id: OMIT, send_days: OMIT, send_hour: OMIT,
|
|
37
|
+
time_zone: OMIT, active: OMIT, repeat: OMIT, hold: OMIT, exclude_subscriber_sources: OMIT)
|
|
38
|
+
body = given(name: name, email_address: email_address, email_template_id: email_template_id,
|
|
39
|
+
send_days: send_days, send_hour: send_hour, time_zone: time_zone, active: active,
|
|
40
|
+
repeat: repeat, hold: hold, exclude_subscriber_sources: exclude_subscriber_sources)
|
|
41
|
+
one(:put, "/v4/sequences/#{path_id(id)}", "sequence", Objects::Sequence, body: body)
|
|
31
42
|
end
|
|
32
43
|
|
|
33
44
|
# DELETE /v4/sequences/:id
|
|
34
45
|
def delete(id)
|
|
35
|
-
http_delete("/v4/sequences/#{id}")
|
|
46
|
+
http_delete("/v4/sequences/#{path_id(id)}")
|
|
36
47
|
nil
|
|
37
48
|
end
|
|
38
49
|
|
|
39
50
|
# POST /v4/sequences/:sequence_id/subscribers/:subscriber_id
|
|
40
51
|
def add_subscriber(sequence_id, subscriber_id)
|
|
41
|
-
one(:post, "/v4/sequences/#{sequence_id}/subscribers/#{subscriber_id}", "subscriber", Objects::Subscriber)
|
|
52
|
+
one(:post, "/v4/sequences/#{path_id(sequence_id)}/subscribers/#{path_id(subscriber_id)}", "subscriber", Objects::Subscriber)
|
|
42
53
|
end
|
|
43
54
|
|
|
44
55
|
# POST /v4/sequences/:sequence_id/subscribers
|
|
45
56
|
def add_subscriber_by_email(sequence_id, email_address:)
|
|
46
|
-
one(:post, "/v4/sequences/#{sequence_id}/subscribers", "subscriber", Objects::Subscriber,
|
|
57
|
+
one(:post, "/v4/sequences/#{path_id(sequence_id)}/subscribers", "subscriber", Objects::Subscriber,
|
|
47
58
|
body: { email_address: email_address })
|
|
48
59
|
end
|
|
49
60
|
|
|
50
61
|
# GET /v4/sequences/:sequence_id/emails
|
|
51
62
|
def emails(sequence_id, **params)
|
|
52
|
-
collection("/v4/sequences/#{sequence_id}/emails", "emails", Objects::SequenceEmail, params)
|
|
63
|
+
collection("/v4/sequences/#{path_id(sequence_id)}/emails", "emails", Objects::SequenceEmail, params)
|
|
53
64
|
end
|
|
54
65
|
|
|
55
|
-
# GET /v4/sequences/:sequence_id/emails/:id
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
# GET /v4/sequences/:sequence_id/emails/:id — include: "stats" embeds the
|
|
67
|
+
# email's performance stats.
|
|
68
|
+
def email(sequence_id, id, include: nil)
|
|
69
|
+
one(:get, "/v4/sequences/#{path_id(sequence_id)}/emails/#{path_id(id)}", "email", Objects::SequenceEmail,
|
|
70
|
+
params: { include: include }.compact)
|
|
58
71
|
end
|
|
59
72
|
|
|
60
|
-
# POST /v4/sequences/:sequence_id/emails
|
|
61
|
-
#
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
# POST /v4/sequences/:sequence_id/emails. `delay_unit` is "days" or
|
|
74
|
+
# "hours"; `send_days` nil resets to all seven days; `position` is
|
|
75
|
+
# zero-based and defaults to last.
|
|
76
|
+
def create_email(sequence_id, subject:, delay_value:, delay_unit:, preview_text: OMIT, content: OMIT,
|
|
77
|
+
email_template_id: OMIT, published: OMIT, send_days: OMIT, position: OMIT)
|
|
78
|
+
body = given(subject: subject, delay_value: delay_value, delay_unit: delay_unit, preview_text: preview_text,
|
|
79
|
+
content: content, email_template_id: email_template_id, published: published,
|
|
80
|
+
send_days: send_days, position: position)
|
|
81
|
+
one(:post, "/v4/sequences/#{path_id(sequence_id)}/emails", "email", Objects::SequenceEmail, body: body)
|
|
64
82
|
end
|
|
65
83
|
|
|
66
|
-
# PUT /v4/sequences/:sequence_id/emails/:id
|
|
67
|
-
|
|
68
|
-
|
|
84
|
+
# PUT /v4/sequences/:sequence_id/emails/:id — only the fields passed
|
|
85
|
+
# change; pass nil for email_template_id or send_days to clear them.
|
|
86
|
+
def update_email(sequence_id, id, subject: OMIT, delay_value: OMIT, delay_unit: OMIT, preview_text: OMIT,
|
|
87
|
+
content: OMIT, email_template_id: OMIT, published: OMIT, send_days: OMIT, position: OMIT)
|
|
88
|
+
body = given(subject: subject, delay_value: delay_value, delay_unit: delay_unit, preview_text: preview_text,
|
|
89
|
+
content: content, email_template_id: email_template_id, published: published,
|
|
90
|
+
send_days: send_days, position: position)
|
|
91
|
+
one(:put, "/v4/sequences/#{path_id(sequence_id)}/emails/#{path_id(id)}", "email", Objects::SequenceEmail,
|
|
92
|
+
body: body)
|
|
69
93
|
end
|
|
70
94
|
|
|
71
95
|
# DELETE /v4/sequences/:sequence_id/emails/:id
|
|
72
96
|
def delete_email(sequence_id, id)
|
|
73
|
-
http_delete("/v4/sequences/#{sequence_id}/emails/#{id}")
|
|
97
|
+
http_delete("/v4/sequences/#{path_id(sequence_id)}/emails/#{path_id(id)}")
|
|
74
98
|
nil
|
|
75
99
|
end
|
|
76
100
|
end
|
|
@@ -11,18 +11,23 @@ module Kit
|
|
|
11
11
|
|
|
12
12
|
# GET /v4/snippets/:id
|
|
13
13
|
def get(id)
|
|
14
|
-
one(:get, "/v4/snippets/#{id}", "snippet", Objects::Snippet)
|
|
14
|
+
one(:get, "/v4/snippets/#{path_id(id)}", "snippet", Objects::Snippet)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
|
-
# POST /v4/snippets
|
|
18
|
-
#
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
# POST /v4/snippets. An "inline" snippet carries Liquid text in
|
|
18
|
+
# `content`; a "block" snippet carries HTML in
|
|
19
|
+
# `document_attributes: { value_html: ... }`.
|
|
20
|
+
def create(name:, snippet_type:, content: OMIT, document_attributes: OMIT)
|
|
21
|
+
body = given(name: name, snippet_type: snippet_type, content: content,
|
|
22
|
+
document_attributes: document_attributes)
|
|
23
|
+
one(:post, "/v4/snippets", "snippet", Objects::Snippet, body: body)
|
|
21
24
|
end
|
|
22
25
|
|
|
23
|
-
# PUT /v4/snippets/:id
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
# PUT /v4/snippets/:id — rename, archive/restore, or replace the content
|
|
27
|
+
# (snippet_type cannot change).
|
|
28
|
+
def update(id, name: OMIT, archived: OMIT, content: OMIT, document_attributes: OMIT)
|
|
29
|
+
body = given(name: name, archived: archived, content: content, document_attributes: document_attributes)
|
|
30
|
+
one(:put, "/v4/snippets/#{path_id(id)}", "snippet", Objects::Snippet, body: body)
|
|
26
31
|
end
|
|
27
32
|
end
|
|
28
33
|
end
|
|
@@ -13,7 +13,7 @@ module Kit
|
|
|
13
13
|
|
|
14
14
|
# GET /v4/subscribers/:id
|
|
15
15
|
def get(id)
|
|
16
|
-
one(:get, "/v4/subscribers/#{id}", "subscriber", Objects::Subscriber)
|
|
16
|
+
one(:get, "/v4/subscribers/#{path_id(id)}", "subscriber", Objects::Subscriber)
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
# POST /v4/subscribers — email_address required; first_name, state, fields optional.
|
|
@@ -26,12 +26,17 @@ module Kit
|
|
|
26
26
|
# PUT /v4/subscribers/:id
|
|
27
27
|
def update(id, first_name: nil, email_address: nil, fields: nil)
|
|
28
28
|
body = { first_name: first_name, email_address: email_address, fields: fields }.compact
|
|
29
|
-
one(:put, "/v4/subscribers/#{id}", "subscriber", Objects::Subscriber, body: body)
|
|
29
|
+
one(:put, "/v4/subscribers/#{path_id(id)}", "subscriber", Objects::Subscriber, body: body)
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
# POST /v4/subscribers/:id/unsubscribe
|
|
32
|
+
# POST /v4/subscribers/:id/unsubscribe — the API answers 204 with no body,
|
|
33
|
+
# so this returns nil. Should Kit ever echo the subscriber back, it is
|
|
34
|
+
# returned as a Subscriber instead of being discarded.
|
|
33
35
|
def unsubscribe(id)
|
|
34
|
-
|
|
36
|
+
body = http_post("/v4/subscribers/#{path_id(id)}/unsubscribe")
|
|
37
|
+
return nil unless body.is_a?(Hash) && body.key?("subscriber")
|
|
38
|
+
|
|
39
|
+
Objects::Subscriber.from(body.fetch("subscriber"))
|
|
35
40
|
end
|
|
36
41
|
|
|
37
42
|
# POST /v4/subscribers/filter — the same filters as #list, sent in the
|
|
@@ -42,25 +47,33 @@ module Kit
|
|
|
42
47
|
|
|
43
48
|
# GET /v4/subscribers/:id/tags — the tags applied to a subscriber.
|
|
44
49
|
def tags(id, **params)
|
|
45
|
-
collection("/v4/subscribers/#{id}/tags", "tags", Objects::Tag, params)
|
|
50
|
+
collection("/v4/subscribers/#{path_id(id)}/tags", "tags", Objects::Tag, params)
|
|
46
51
|
end
|
|
47
52
|
|
|
48
|
-
# GET /v4/subscribers/:id/stats — engagement stats.
|
|
49
|
-
#
|
|
50
|
-
def stats(id)
|
|
51
|
-
|
|
53
|
+
# GET /v4/subscribers/:id/stats — the subscriber's engagement stats.
|
|
54
|
+
# Bound the window with email_sent_after / email_sent_before (yyyy-mm-dd).
|
|
55
|
+
def stats(id, email_sent_after: nil, email_sent_before: nil)
|
|
56
|
+
params = { email_sent_after: email_sent_after, email_sent_before: email_sent_before }.compact
|
|
57
|
+
one(:get, "/v4/subscribers/#{path_id(id)}/stats", "subscriber", Objects::SubscriberStats, params: params)
|
|
52
58
|
end
|
|
53
59
|
|
|
54
60
|
# POST /v4/subscribers/:id/location — set the subscriber's location
|
|
55
61
|
# (a hash of city/state_province/country_code/latitude/longitude/timezone).
|
|
56
62
|
def set_location(id, location:)
|
|
57
|
-
one(:post, "/v4/subscribers/#{id}/location", "subscriber", Objects::Subscriber,
|
|
63
|
+
one(:post, "/v4/subscribers/#{path_id(id)}/location", "subscriber", Objects::Subscriber,
|
|
64
|
+
body: { location: location })
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
# PATCH /v4/subscribers/:id/location — replace a pinned location. Kit
|
|
68
|
+
# requires the full location (all six keys) on update, not a partial.
|
|
69
|
+
def update_location(id, location:)
|
|
70
|
+
one(:patch, "/v4/subscribers/#{path_id(id)}/location", "subscriber", Objects::Subscriber,
|
|
58
71
|
body: { location: location })
|
|
59
72
|
end
|
|
60
73
|
|
|
61
74
|
# DELETE /v4/subscribers/:id/location
|
|
62
75
|
def remove_location(id)
|
|
63
|
-
http_delete("/v4/subscribers/#{id}/location")
|
|
76
|
+
http_delete("/v4/subscribers/#{path_id(id)}/location")
|
|
64
77
|
nil
|
|
65
78
|
end
|
|
66
79
|
end
|
data/lib/kit/resources/tags.rb
CHANGED
|
@@ -16,36 +16,36 @@ module Kit
|
|
|
16
16
|
|
|
17
17
|
# PUT /v4/tags/:id
|
|
18
18
|
def update(id, name:)
|
|
19
|
-
one(:put, "/v4/tags/#{id}", "tag", Objects::Tag, body: { name: name })
|
|
19
|
+
one(:put, "/v4/tags/#{path_id(id)}", "tag", Objects::Tag, body: { name: name })
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
# POST /v4/tags/:tag_id/subscribers/:id
|
|
23
23
|
def tag_subscriber(tag_id, subscriber_id)
|
|
24
|
-
one(:post, "/v4/tags/#{tag_id}/subscribers/#{subscriber_id}", "subscriber", Objects::Subscriber)
|
|
24
|
+
one(:post, "/v4/tags/#{path_id(tag_id)}/subscribers/#{path_id(subscriber_id)}", "subscriber", Objects::Subscriber)
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
# DELETE /v4/tags/:tag_id/subscribers/:id
|
|
28
28
|
def remove_subscriber(tag_id, subscriber_id)
|
|
29
|
-
http_delete("/v4/tags/#{tag_id}/subscribers/#{subscriber_id}")
|
|
29
|
+
http_delete("/v4/tags/#{path_id(tag_id)}/subscribers/#{path_id(subscriber_id)}")
|
|
30
30
|
nil
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
# POST /v4/tags/:tag_id/subscribers — tag a subscriber by email address.
|
|
34
34
|
def tag_subscriber_by_email(tag_id, email_address:)
|
|
35
|
-
one(:post, "/v4/tags/#{tag_id}/subscribers", "subscriber", Objects::Subscriber,
|
|
35
|
+
one(:post, "/v4/tags/#{path_id(tag_id)}/subscribers", "subscriber", Objects::Subscriber,
|
|
36
36
|
body: { email_address: email_address })
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
# DELETE /v4/tags/:tag_id/subscribers — remove a tag from a subscriber by
|
|
40
40
|
# email address (passed as a query parameter).
|
|
41
41
|
def remove_subscriber_by_email(tag_id, email_address:)
|
|
42
|
-
http_delete("/v4/tags/#{tag_id}/subscribers", params: { email_address: email_address })
|
|
42
|
+
http_delete("/v4/tags/#{path_id(tag_id)}/subscribers", params: { email_address: email_address })
|
|
43
43
|
nil
|
|
44
44
|
end
|
|
45
45
|
|
|
46
46
|
# GET /v4/tags/:tag_id/subscribers
|
|
47
47
|
def subscribers(tag_id, **params)
|
|
48
|
-
collection("/v4/tags/#{tag_id}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
48
|
+
collection("/v4/tags/#{path_id(tag_id)}/subscribers", "subscribers", Objects::Subscriber, params)
|
|
49
49
|
end
|
|
50
50
|
end
|
|
51
51
|
end
|