mailerlite-ruby 1.0.6 → 2.1.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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/.envrc +2 -0
  3. data/.github/workflows/main.yml +4 -4
  4. data/.github/workflows/publish_gem.yml +5 -5
  5. data/.gitignore +2 -1
  6. data/.rubocop.yml +1 -1
  7. data/CHANGELOG.md +21 -0
  8. data/README.md +583 -1
  9. data/flake.lock +27 -0
  10. data/flake.nix +25 -0
  11. data/lefthook.yml +14 -0
  12. data/lib/mailerlite/api_response.rb +24 -0
  13. data/lib/mailerlite/automations/automation_emails.rb +57 -0
  14. data/lib/mailerlite/automations/automation_reports.rb +114 -0
  15. data/lib/mailerlite/automations/automation_steps.rb +105 -0
  16. data/lib/mailerlite/automations/automation_templates.rb +34 -0
  17. data/lib/mailerlite/automations/automation_triggers.rb +62 -0
  18. data/lib/mailerlite/automations/automations.rb +177 -8
  19. data/lib/mailerlite/brand_styles/brand_styles.rb +24 -0
  20. data/lib/mailerlite/campaigns/campaigns.rb +33 -1
  21. data/lib/mailerlite/client.rb +15 -5
  22. data/lib/mailerlite/ecommerce/ecommerce.rb +316 -0
  23. data/lib/mailerlite/emails/emails.rb +306 -0
  24. data/lib/mailerlite/errors.rb +88 -0
  25. data/lib/mailerlite/files/files.rb +45 -0
  26. data/lib/mailerlite/groups/groups.rb +16 -8
  27. data/lib/mailerlite/params.rb +58 -0
  28. data/lib/mailerlite/query_params.rb +33 -0
  29. data/lib/mailerlite/request.rb +24 -0
  30. data/lib/mailerlite/segments/segments.rb +10 -10
  31. data/lib/mailerlite/subscribers/subscribers.rb +63 -8
  32. data/lib/mailerlite/version.rb +1 -1
  33. data/lib/mailerlite.rb +14 -0
  34. data/mailerlite-ruby.gemspec +8 -8
  35. data/spec/api_response_rspec.rb +140 -0
  36. data/spec/automation_emails_rspec.rb +40 -0
  37. data/spec/automation_reports_rspec.rb +92 -0
  38. data/spec/automation_steps_rspec.rb +76 -0
  39. data/spec/automation_templates_rspec.rb +24 -0
  40. data/spec/automation_triggers_rspec.rb +48 -0
  41. data/spec/automations_rspec.rb +143 -0
  42. data/spec/brand_styles_rspec.rb +49 -0
  43. data/spec/campaigns_rspec.rb +42 -0
  44. data/spec/ecommerce_rspec.rb +141 -0
  45. data/spec/emails_rspec.rb +692 -0
  46. data/spec/files_rspec.rb +90 -0
  47. data/spec/fixtures/brand_styles.json +50 -0
  48. data/spec/fixtures/campaign_simple_editor.json +24 -0
  49. data/spec/fixtures/email.json +81 -0
  50. data/spec/fixtures/email_block.json +12 -0
  51. data/spec/fixtures/email_block_created.json +12 -0
  52. data/spec/fixtures/email_block_created_rejected.json +15 -0
  53. data/spec/fixtures/email_block_moved.json +12 -0
  54. data/spec/fixtures/email_block_updated.json +9 -0
  55. data/spec/fixtures/email_block_updated_rejected.json +13 -0
  56. data/spec/fixtures/email_block_validation_invalid.json +5 -0
  57. data/spec/fixtures/email_etag.json +1 -0
  58. data/spec/fixtures/email_html.json +1 -0
  59. data/spec/fixtures/email_settings.json +111 -0
  60. data/spec/fixtures/email_settings_validation.json +9 -0
  61. data/spec/fixtures/email_template.json +1 -0
  62. data/spec/fixtures/email_version.json +1 -0
  63. data/spec/fixtures/email_versions.json +26 -0
  64. data/spec/fixtures/files.json +44 -0
  65. data/spec/groups_rspec.rb +21 -0
  66. data/spec/params_rspec.rb +126 -0
  67. data/spec/request_rspec.rb +139 -0
  68. data/spec/segments_rspec.rb +39 -0
  69. data/spec/spec_helper.rb +1 -0
  70. data/spec/subscribers_rspec.rb +57 -0
  71. data/spec/support/json_fixture.rb +27 -0
  72. data/spec/support/request_stub.rb +25 -0
  73. metadata +69 -22
  74. /data/{renovate.json → .github/renovate.json} +0 -0
@@ -3,6 +3,9 @@
3
3
  module MailerLite
4
4
  # This is a class for manipulating the Campaigns from MailerLite API.
5
5
  class Campaigns
6
+ # The value of `editor` in the emails of `create` for the simple editor.
7
+ EDITOR_SIMPLE = 'simple'
8
+
6
9
  attr_reader :client
7
10
 
8
11
  # Inits the `Campaigns` class with the specified `client`.
@@ -34,7 +37,13 @@ module MailerLite
34
37
  # @param name [String] Maximum string length of 255 characters
35
38
  # @param language_id [integer] Used to define the language in the unsubscribe template. Must be a valid language id. Defaults to english
36
39
  # @param type [String] Must be one of the following: regular, ab, resend. Type resend is only available for accounts on growing or advanced plans
37
- # @param emails [Array] Must contain 1 email object item
40
+ # @param emails [Array] Must contain 1 email object item. The SDK sends each email as it is. An email can also have these keys:
41
+ # - `editor`: set it to `simple` (`EDITOR_SIMPLE`) to create the email in the simple editor. Do not send `content` with it.
42
+ # It must be the same on every email of the campaign. It is not available on every plan: for an account on a plan without it, the API returns an error.
43
+ # - `template_id`: the simple editor template that the email starts from. It is a template from the shared gallery, or a template that you saved from your own email
44
+ # with `Emails#create_template` (the `id` in its response). It is optional, and allowed only when `editor` is `simple`. Without it, the email starts from the
45
+ # default blank template. The API copies the template into the new email and does not change the template. It must be the same on every email of the campaign.
46
+ # Then edit the email with `MailerLite::Emails`. Its ID is in `data.emails[0].id` of the response.
38
47
  # @param groups [Array] Must contain valid group ids belonging to the account
39
48
  # @param segments [Array] Must contain valid segment ids belonging to the account. If both groups and segments are provided, only segments are used
40
49
  # @param ab_settings [Array<Array>] only if type is ab - All items of the array are required
@@ -82,6 +91,7 @@ module MailerLite
82
91
  end
83
92
 
84
93
  # Update a new campaign with the specified details.
94
+ # Only `create` accepts `editor` and `template_id`.
85
95
  #
86
96
  # @param campaign_id [Integer] the ID of the campaign to update
87
97
  # @param name [String] Maximum string length of 255 characters
@@ -212,5 +222,27 @@ module MailerLite
212
222
  def languages
213
223
  client.http.get("#{MAILERLITE_API_URL}/campaigns/languages")
214
224
  end
225
+
226
+ # Returns the orders and revenue a campaign earned in one shop
227
+ #
228
+ # @param campaign_id [String] the ID of the campaign
229
+ # @param shop_id [String] the ID of the shop
230
+ # @return [HTTP::Response] the response from the API
231
+ def ecommerce_stats(campaign_id:, shop_id:)
232
+ uri = URI("#{MAILERLITE_API_URL}/campaigns/#{campaign_id}/reports/ecommerce")
233
+ uri.query = URI.encode_www_form('shop_id' => shop_id)
234
+ client.http.get(uri)
235
+ end
236
+
237
+ # Returns the orders attributed to a campaign in one shop
238
+ #
239
+ # @param campaign_id [String] the ID of the campaign
240
+ # @param shop_id [String] the ID of the shop
241
+ # @return [HTTP::Response] the response from the API
242
+ def ecommerce_orders(campaign_id:, shop_id:, page: nil, limit: nil)
243
+ uri = URI("#{MAILERLITE_API_URL}/campaigns/#{campaign_id}/reports/ecommerce/orders")
244
+ uri.query = URI.encode_www_form({ 'shop_id' => shop_id, 'page' => page, 'limit' => limit }.compact)
245
+ client.http.get(uri)
246
+ end
215
247
  end
216
248
  end
@@ -1,20 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'http'
4
- require 'dotenv/load'
5
4
 
6
5
  MAILERLITE_API_URL = 'https://connect.mailerlite.com/api'
7
6
 
8
- Dotenv.require_keys('MAILERLITE_API_TOKEN')
9
-
10
7
  # mailerlite-ruby is a gem that integrates all endpoints from MailerLite API
11
8
  module MailerLite
12
9
  attr_reader :api_token
13
10
 
11
+ class << self
12
+ attr_accessor :use_dotenv
13
+
14
+ def configure
15
+ yield self
16
+ end
17
+ end
18
+
14
19
  # Inits the client.
15
20
  class Client
16
- def initialize(api_token = ENV.fetch('MAILERLITE_API_TOKEN', nil))
17
- @api_token = api_token
21
+ def initialize
22
+ if MailerLite.use_dotenv
23
+ require 'dotenv'
24
+ Dotenv.load
25
+ Dotenv.require_keys('MAILERLITE_API_TOKEN')
26
+ end
27
+ @api_token = ENV.fetch('MAILERLITE_API_TOKEN', nil)
18
28
  end
19
29
 
20
30
  def headers
@@ -0,0 +1,316 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MailerLite
4
+ # Classes for manipulating e-commerce data from MailerLite API.
5
+ module Ecommerce
6
+ # Shared setup for the e-commerce classes.
7
+ class Resource
8
+ attr_reader :client
9
+
10
+ # Inits the class with the specified `client`.
11
+ #
12
+ # @param client [MailerLite::Client] the `Client` instance to use
13
+ def initialize(client: MailerLite::Client.new)
14
+ @client = client
15
+ end
16
+
17
+ private
18
+
19
+ def shop_url(shop_id, path = '')
20
+ "#{MAILERLITE_API_URL}/ecommerce/shops/#{shop_id}#{path}"
21
+ end
22
+
23
+ def get_with_query(url, filter: {}, **params)
24
+ query = filter.to_h { |key, value| ["filter[#{key}]", value] }.merge(params.transform_keys(&:to_s)).compact
25
+ uri = URI(url)
26
+ uri.query = URI.encode_www_form(query) unless query.empty?
27
+ client.http.get(uri)
28
+ end
29
+ end
30
+
31
+ # Shops from MailerLite API.
32
+ class Shops < Resource
33
+ # @return [HTTP::Response] the response from the API
34
+ def list(page: nil, limit: nil)
35
+ get_with_query("#{MAILERLITE_API_URL}/ecommerce/shops", page: page, limit: limit)
36
+ end
37
+
38
+ # @param shop_id [String] the ID of the shop
39
+ # @return [HTTP::Response] the response from the API
40
+ def get(shop_id)
41
+ client.http.get(shop_url(shop_id))
42
+ end
43
+
44
+ # @param params [Hash] name, url and currency are required
45
+ # @return [HTTP::Response] the response from the API
46
+ def create(params)
47
+ client.http.post("#{MAILERLITE_API_URL}/ecommerce/shops", json: params)
48
+ end
49
+
50
+ # @return [HTTP::Response] the response from the API
51
+ def update(shop_id:, params:)
52
+ client.http.put(shop_url(shop_id), json: params)
53
+ end
54
+
55
+ # @return [HTTP::Response] the response from the API
56
+ def delete(shop_id)
57
+ client.http.delete(shop_url(shop_id))
58
+ end
59
+
60
+ # @param start_date [String] the first day, e.g. 2026-01-01
61
+ # @param end_date [String] the last day, included
62
+ # @return [HTTP::Response] the response from the API
63
+ def stats(shop_id:, start_date:, end_date:)
64
+ get_with_query(shop_url(shop_id, '/reports/stats'), start_date: start_date, end_date: end_date)
65
+ end
66
+ end
67
+
68
+ # Products from MailerLite API.
69
+ class Products < Resource
70
+ # @param filter [Hash] name, type, enabled, category or exclude_from_automations
71
+ # @return [HTTP::Response] the response from the API
72
+ def list(shop_id:, filter: {}, sort: nil, page: nil, limit: nil)
73
+ get_with_query(shop_url(shop_id, '/products'), filter: filter, sort: sort, page: page, limit: limit)
74
+ end
75
+
76
+ # @return [HTTP::Response] the response from the API
77
+ def get(shop_id:, product_id:)
78
+ client.http.get(shop_url(shop_id, "/products/#{product_id}"))
79
+ end
80
+
81
+ # @return [HTTP::Response] the response from the API
82
+ def create(shop_id:, params:)
83
+ client.http.post(shop_url(shop_id, '/products'), json: params)
84
+ end
85
+
86
+ # @return [HTTP::Response] the response from the API
87
+ def update(shop_id:, product_id:, params:)
88
+ client.http.put(shop_url(shop_id, "/products/#{product_id}"), json: params)
89
+ end
90
+
91
+ # @return [HTTP::Response] the response from the API
92
+ def delete(shop_id:, product_id:)
93
+ client.http.delete(shop_url(shop_id, "/products/#{product_id}"))
94
+ end
95
+
96
+ # @param enabled [Boolean] whether the product is enabled
97
+ # @return [HTTP::Response] the response from the API
98
+ def change_status(shop_id:, product_id:, enabled:)
99
+ client.http.put(shop_url(shop_id, "/products/#{product_id}/change-status"), json: { status: enabled })
100
+ end
101
+
102
+ # @param replace [Boolean] also remove the categories that are not listed
103
+ # @return [HTTP::Response] the response from the API
104
+ def assign_categories(shop_id:, product_id:, category_ids:, replace: false)
105
+ client.http.put(shop_url(shop_id, "/products/#{product_id}/categories/multiple"), json: { categories: category_ids, replace: replace })
106
+ end
107
+ end
108
+
109
+ # Product variants from MailerLite API.
110
+ class ProductVariants < Resource
111
+ # @return [HTTP::Response] the response from the API
112
+ def list(shop_id:, product_id:)
113
+ client.http.get(shop_url(shop_id, "/products/#{product_id}/variants"))
114
+ end
115
+
116
+ # @param variants [Array<Hash>] name and attributes are required
117
+ # @return [HTTP::Response] the response from the API
118
+ def sync(shop_id:, product_id:, variants:)
119
+ client.http.post(shop_url(shop_id, "/products/#{product_id}/variants"), json: variants)
120
+ end
121
+
122
+ # @return [HTTP::Response] the response from the API
123
+ def update(shop_id:, product_id:, variant_id:, params:)
124
+ client.http.put(shop_url(shop_id, "/products/#{product_id}/variants/#{variant_id}"), json: params)
125
+ end
126
+
127
+ # @return [HTTP::Response] the response from the API
128
+ def delete(shop_id:, product_id:, variant_id:)
129
+ client.http.delete(shop_url(shop_id, "/products/#{product_id}/variants/#{variant_id}"))
130
+ end
131
+ end
132
+
133
+ # Categories from MailerLite API.
134
+ class Categories < Resource
135
+ # @return [HTTP::Response] the response from the API
136
+ def list(shop_id:, filter: {}, page: nil, limit: nil)
137
+ get_with_query(shop_url(shop_id, '/categories'), filter: filter, page: page, limit: limit)
138
+ end
139
+
140
+ # @return [HTTP::Response] the response from the API
141
+ def get(shop_id:, category_id:)
142
+ client.http.get(shop_url(shop_id, "/categories/#{category_id}"))
143
+ end
144
+
145
+ # @return [HTTP::Response] the response from the API
146
+ def create(shop_id:, params:)
147
+ client.http.post(shop_url(shop_id, '/categories'), json: params)
148
+ end
149
+
150
+ # @return [HTTP::Response] the response from the API
151
+ def update(shop_id:, category_id:, params:)
152
+ client.http.put(shop_url(shop_id, "/categories/#{category_id}"), json: params)
153
+ end
154
+
155
+ # @return [HTTP::Response] the response from the API
156
+ def delete(shop_id:, category_id:)
157
+ client.http.delete(shop_url(shop_id, "/categories/#{category_id}"))
158
+ end
159
+
160
+ # @return [HTTP::Response] the response from the API
161
+ def products(shop_id:, category_id:, page: nil, limit: nil)
162
+ get_with_query(shop_url(shop_id, "/categories/#{category_id}/products"), page: page, limit: limit)
163
+ end
164
+
165
+ # @return [HTTP::Response] the response from the API
166
+ def assign_product(shop_id:, category_id:, product_id:)
167
+ client.http.put(shop_url(shop_id, "/categories/#{category_id}/products/#{product_id}"))
168
+ end
169
+
170
+ # @return [HTTP::Response] the response from the API
171
+ def unassign_product(shop_id:, category_id:, product_id:)
172
+ client.http.delete(shop_url(shop_id, "/categories/#{category_id}/products/#{product_id}"))
173
+ end
174
+ end
175
+
176
+ # Customers from MailerLite API.
177
+ class Customers < Resource
178
+ # @param filter [Hash] email
179
+ # @return [HTTP::Response] the response from the API
180
+ def list(shop_id:, filter: {}, sort: nil, page: nil, limit: nil)
181
+ get_with_query(shop_url(shop_id, '/customers'), filter: filter, sort: sort, page: page, limit: limit)
182
+ end
183
+
184
+ # @return [HTTP::Response] the response from the API
185
+ def get(shop_id:, customer_id:)
186
+ client.http.get(shop_url(shop_id, "/customers/#{customer_id}"))
187
+ end
188
+
189
+ # @return [HTTP::Response] the response from the API
190
+ def create(shop_id:, params:)
191
+ client.http.post(shop_url(shop_id, '/customers'), json: params)
192
+ end
193
+
194
+ # @return [HTTP::Response] the response from the API
195
+ def update(shop_id:, customer_id:, params:)
196
+ client.http.put(shop_url(shop_id, "/customers/#{customer_id}"), json: params)
197
+ end
198
+
199
+ # @return [HTTP::Response] the response from the API
200
+ def delete(shop_id:, customer_id:)
201
+ client.http.delete(shop_url(shop_id, "/customers/#{customer_id}"))
202
+ end
203
+ end
204
+
205
+ # Orders from MailerLite API.
206
+ class Orders < Resource
207
+ # @param filter [Hash] status, customer, attributed or email_id
208
+ # @return [HTTP::Response] the response from the API
209
+ def list(shop_id:, filter: {}, sort: nil, page: nil, limit: nil)
210
+ get_with_query(shop_url(shop_id, '/orders'), filter: filter, sort: sort, page: page, limit: limit)
211
+ end
212
+
213
+ # @return [HTTP::Response] the response from the API
214
+ def get(shop_id:, order_id:)
215
+ client.http.get(shop_url(shop_id, "/orders/#{order_id}"))
216
+ end
217
+
218
+ # @param params [Hash] customer and cart are required
219
+ # @return [HTTP::Response] the response from the API
220
+ def create(shop_id:, params:)
221
+ client.http.post(shop_url(shop_id, '/orders'), json: params)
222
+ end
223
+
224
+ # @return [HTTP::Response] the response from the API
225
+ def update(shop_id:, order_id:, params:)
226
+ client.http.put(shop_url(shop_id, "/orders/#{order_id}"), json: params)
227
+ end
228
+
229
+ # @return [HTTP::Response] the response from the API
230
+ def delete(shop_id:, order_id:)
231
+ client.http.delete(shop_url(shop_id, "/orders/#{order_id}"))
232
+ end
233
+ end
234
+
235
+ # Carts from MailerLite API.
236
+ class Carts < Resource
237
+ # @return [HTTP::Response] the response from the API
238
+ def list(shop_id:, page: nil, limit: nil)
239
+ get_with_query(shop_url(shop_id, '/carts'), page: page, limit: limit)
240
+ end
241
+
242
+ # @return [HTTP::Response] the response from the API
243
+ def get(shop_id:, cart_id:)
244
+ client.http.get(shop_url(shop_id, "/carts/#{cart_id}"))
245
+ end
246
+
247
+ # @return [HTTP::Response] the response from the API
248
+ def update(shop_id:, cart_id:, params:)
249
+ client.http.put(shop_url(shop_id, "/carts/#{cart_id}"), json: params)
250
+ end
251
+ end
252
+
253
+ # Cart items from MailerLite API.
254
+ class CartItems < Resource
255
+ # @return [HTTP::Response] the response from the API
256
+ def list(shop_id:, cart_id:, page: nil, limit: nil)
257
+ get_with_query(shop_url(shop_id, "/carts/#{cart_id}/items"), page: page, limit: limit)
258
+ end
259
+
260
+ # @return [HTTP::Response] the response from the API
261
+ def get(shop_id:, cart_id:, item_id:)
262
+ client.http.get(shop_url(shop_id, "/carts/#{cart_id}/items/#{item_id}"))
263
+ end
264
+
265
+ # @return [HTTP::Response] the response from the API
266
+ def create(shop_id:, cart_id:, params:)
267
+ client.http.post(shop_url(shop_id, "/carts/#{cart_id}/items"), json: params)
268
+ end
269
+
270
+ # @return [HTTP::Response] the response from the API
271
+ def update(shop_id:, cart_id:, item_id:, params:)
272
+ client.http.put(shop_url(shop_id, "/carts/#{cart_id}/items/#{item_id}"), json: params)
273
+ end
274
+
275
+ # @return [HTTP::Response] the response from the API
276
+ def delete(shop_id:, cart_id:, item_id:)
277
+ client.http.delete(shop_url(shop_id, "/carts/#{cart_id}/items/#{item_id}"))
278
+ end
279
+ end
280
+
281
+ # Bulk imports from MailerLite API.
282
+ class Imports < Resource
283
+ # @param products [Array<Hash>] the products to import
284
+ # @return [HTTP::Response] the response from the API
285
+ def products(shop_id:, products:)
286
+ client.http.post(shop_url(shop_id, '/products/import'), json: products)
287
+ end
288
+
289
+ # @param categories [Array<Hash>] the categories to import
290
+ # @return [HTTP::Response] the response from the API
291
+ def categories(shop_id:, categories:)
292
+ client.http.post(shop_url(shop_id, '/categories/import'), json: categories)
293
+ end
294
+
295
+ # @param customers [Array<Hash>] the customers to import
296
+ # @return [HTTP::Response] the response from the API
297
+ def customers(shop_id:, customers:)
298
+ client.http.post(shop_url(shop_id, '/customers/import'), json: customers)
299
+ end
300
+
301
+ # @param orders [Array<Hash>] the orders to import
302
+ # @return [HTTP::Response] the response from the API
303
+ def orders(shop_id:, orders:)
304
+ client.http.post(shop_url(shop_id, '/orders/import'), json: { orders: orders })
305
+ end
306
+ end
307
+
308
+ # E-commerce tracking settings from MailerLite API.
309
+ class Settings < Resource
310
+ # @return [HTTP::Response] the response from the API
311
+ def get
312
+ client.http.get("#{MAILERLITE_API_URL}/ecommerce/settings")
313
+ end
314
+ end
315
+ end
316
+ end