cakemail-next-gen 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/.env.dist +3 -0
- data/.rspec +3 -0
- data/.rubocop.yml +52 -0
- data/LICENSE +21 -0
- data/README.md +194 -0
- data/Rakefile +12 -0
- data/cakemail.gemspec +29 -0
- data/images/logo.png +0 -0
- data/lib/cakemail/base.rb +248 -0
- data/lib/cakemail/configuration.rb +21 -0
- data/lib/cakemail/connection.rb +52 -0
- data/lib/cakemail/contact.rb +57 -0
- data/lib/cakemail/list.rb +35 -0
- data/lib/cakemail/sender.rb +30 -0
- data/lib/cakemail/token.rb +59 -0
- data/lib/cakemail/version.rb +5 -0
- data/lib/cakemail.rb +21 -0
- data/sig/cakemail.rbs +4 -0
- data/vcr_cassettes/contact_create.yml +45 -0
- data/vcr_cassettes/contact_create_from_list.yml +45 -0
- data/vcr_cassettes/contact_unsubscribe.yml +45 -0
- data/vcr_cassettes/contact_update.yml +45 -0
- data/vcr_cassettes/contacts_all_without_error.yml +45 -0
- data/vcr_cassettes/contacts_delete.yml +45 -0
- data/vcr_cassettes/contacts_for_deletation.yml +45 -0
- data/vcr_cassettes/contacts_for_unsubscribe.yml +45 -0
- data/vcr_cassettes/contacts_for_update.yml +45 -0
- data/vcr_cassettes/contacts_lists.yml +49 -0
- data/vcr_cassettes/create_token.yml +45 -0
- data/vcr_cassettes/create_wrong_token.yml +46 -0
- data/vcr_cassettes/list.yml +46 -0
- data/vcr_cassettes/list_archive.yml +45 -0
- data/vcr_cassettes/list_contacts.yml +45 -0
- data/vcr_cassettes/list_create.yml +46 -0
- data/vcr_cassettes/list_delete.yml +45 -0
- data/vcr_cassettes/list_sender.yml +46 -0
- data/vcr_cassettes/list_unarchive.yml +45 -0
- data/vcr_cassettes/list_update.yml +46 -0
- data/vcr_cassettes/lists.yml +49 -0
- data/vcr_cassettes/lists_count.yml +47 -0
- data/vcr_cassettes/lists_find_in_batches.yml +93 -0
- data/vcr_cassettes/lists_for_archive.yml +50 -0
- data/vcr_cassettes/lists_for_deletation.yml +50 -0
- data/vcr_cassettes/lists_for_unarchive.yml +48 -0
- data/vcr_cassettes/lists_for_update.yml +50 -0
- data/vcr_cassettes/senders.yml +46 -0
- metadata +93 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 95edcd5ef79bdd5c936ed0e1796dea3e69a2c0b9c91b7e8c22d4a96a35bdc022
|
4
|
+
data.tar.gz: 6c9771c0061bd3268833293db53f3b5caecadbf09389303333fa4056674cef11
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7cfcf78af7aed0e39e83d6a507035631046aeeb7eec499b4cf23bbcadcf336ad76083bb5d64c73f65c6a98208a8667c83c421685c6b7785cdb5950a6d3a85cd
|
7
|
+
data.tar.gz: 06db8e184b081f991a2f35bc0ed76affd657a03b91a1545080d627b4a9f576ed261bdf58e02e13c13129e23c9443cbe2667cb681cd91972ba278e18767d7fc6a
|
data/.env.dist
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
Layout/FirstHashElementIndentation:
|
2
|
+
Enabled: false
|
3
|
+
Layout/ArgumentAlignment:
|
4
|
+
Enabled: false
|
5
|
+
Layout/HashAlignment:
|
6
|
+
Enabled: false
|
7
|
+
Style/Documentation:
|
8
|
+
Enabled: false
|
9
|
+
Style/FrozenStringLiteralComment:
|
10
|
+
Enabled: false
|
11
|
+
Style/OptionalBooleanParameter:
|
12
|
+
Enabled: false
|
13
|
+
Style/MethodDefParentheses:
|
14
|
+
Enabled: true
|
15
|
+
Style/StringLiterals:
|
16
|
+
EnforcedStyle: double_quotes
|
17
|
+
Style/RescueStandardError:
|
18
|
+
EnforcedStyle: implicit
|
19
|
+
Naming/VariableNumber:
|
20
|
+
CheckSymbols: false
|
21
|
+
Style/VariableNumber:
|
22
|
+
Enabled: false
|
23
|
+
Style/HashSyntax:
|
24
|
+
EnforcedShorthandSyntax: never
|
25
|
+
Gemspec/RequiredRubyVersion:
|
26
|
+
Enabled: false
|
27
|
+
Style/WordArray:
|
28
|
+
Enabled: false
|
29
|
+
Style/SymbolArray:
|
30
|
+
Enabled: false
|
31
|
+
Lint/Debugger:
|
32
|
+
Enabled: false
|
33
|
+
Layout/MultilineMethodCallIndentation:
|
34
|
+
Enabled: false
|
35
|
+
Style/TrailingCommaInArguments:
|
36
|
+
EnforcedStyleForMultiline: comma
|
37
|
+
Layout/ArrayAlignment:
|
38
|
+
EnforcedStyle: with_fixed_indentation
|
39
|
+
Style/ClassVars:
|
40
|
+
Enabled: false
|
41
|
+
Metrics/BlockLength:
|
42
|
+
Max: 2000
|
43
|
+
Metrics/MethodLength:
|
44
|
+
Max: 25
|
45
|
+
Metrics/PerceivedComplexity:
|
46
|
+
Max: 15
|
47
|
+
Metrics/AbcSize:
|
48
|
+
Max: 25
|
49
|
+
Metrics/CyclomaticComplexity:
|
50
|
+
Max: 20
|
51
|
+
Metrics/ClassLength:
|
52
|
+
Max: 250
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2023 Nathan Lopez
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
<p align="center">
|
2
|
+
<img src="images/logo.png" alt="Cakemail Next-gen" />
|
3
|
+
</p>
|
4
|
+
|
5
|
+
# Cakemail Next-gen Ruby wrapper
|
6
|
+
|
7
|
+
<span>[](https://rubygems.org/gems/cakemail-next-gen)</span> <span>
|
8
|
+
[](https://github.com/andrewdsilva/cakemail-ruby)</span> <span>
|
9
|
+
</span> <span>
|
10
|
+
[](http://opensource.org/licenses/MIT)</span> <span>
|
11
|
+
</span>
|
12
|
+
|
13
|
+
This library allows you to quickly and easily use the Cakemail Next-gen API via Ruby.
|
14
|
+
|
15
|
+
This gem is designed to be community-driven, with the aim of prioritizing the needs and preferences of its users. Your active involvement is crucial in shaping the future development of this project. You can contribute by creating issues and pull requests, as well as engaging with existing ones through upvoting or commenting.
|
16
|
+
|
17
|
+
If you need help using Cakemail, please check the Cakemail Support Help Center at https://www.cakemail.com/contact-us.
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
To install the gem add it into a Gemfile (Bundler):
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
gem "cakemail-next-gen"
|
25
|
+
```
|
26
|
+
|
27
|
+
And then execute:
|
28
|
+
|
29
|
+
```
|
30
|
+
bundle install
|
31
|
+
```
|
32
|
+
|
33
|
+
## API key
|
34
|
+
|
35
|
+
You need to set your Cakemail API credentials using environment variables.
|
36
|
+
|
37
|
+
```ruby
|
38
|
+
# .env
|
39
|
+
CAKEMAIL_API_KEY="..."
|
40
|
+
CAKEMAIL_USERNAME="..."
|
41
|
+
CAKEMAIL_PASSWORD="..."
|
42
|
+
```
|
43
|
+
|
44
|
+
If you wish to generate a new token, you will need the environment variables `CAKEMAIL_USERNAME` and `CAKEMAIL_PASSWORD`.
|
45
|
+
|
46
|
+
If you already have a token, you will only need: `CAKEMAIL_API_KEY`.
|
47
|
+
|
48
|
+
### Generating a Token
|
49
|
+
|
50
|
+
To generate a token, follow these steps:
|
51
|
+
|
52
|
+
1. Set the `CAKEMAIL_USERNAME` and `CAKEMAIL_PASSWORD` environment variables using a `.env` file.
|
53
|
+
2. Use the `Cakemail::Token.create` method provided by the gem to generate a token. Here's an example of how to use it :
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
token = Cakemail::Token.create
|
57
|
+
|
58
|
+
pp "Access token created is #{token.access_token}"
|
59
|
+
```
|
60
|
+
|
61
|
+
## Usage
|
62
|
+
|
63
|
+
Cakemail-Ruby was designed with usability as its primary goal, so that you can forget the API and intuitively interact with your lists, contacts, campaigns and so on.
|
64
|
+
|
65
|
+
## Lists
|
66
|
+
|
67
|
+
Here are some basic usage examples for managing lists:
|
68
|
+
|
69
|
+
1. Fetching all lists:
|
70
|
+
```ruby
|
71
|
+
lists = Cakemail::List.all
|
72
|
+
lists.each do |list|
|
73
|
+
puts "List ID: #{list.id}"
|
74
|
+
puts "List Name: #{list.name}"
|
75
|
+
# Additional list attributes can be accessed here
|
76
|
+
end
|
77
|
+
```
|
78
|
+
|
79
|
+
2. Creating a new list:
|
80
|
+
```ruby
|
81
|
+
new_list = Cakemail::List.create(name: "New List")
|
82
|
+
puts "Created List ID: #{new_list.id}"
|
83
|
+
puts "Created List Name: #{new_list.name}"
|
84
|
+
```
|
85
|
+
|
86
|
+
3. Updating an existing list:
|
87
|
+
```ruby
|
88
|
+
list = Cakemail::List.find(list_id)
|
89
|
+
list.update(name: "New name")
|
90
|
+
puts "Updated List Name: #{list.name}"
|
91
|
+
```
|
92
|
+
|
93
|
+
4. Deleting a list:
|
94
|
+
```ruby
|
95
|
+
list = Cakemail::List.find(list_id)
|
96
|
+
list.delete
|
97
|
+
puts "List deleted successfully."
|
98
|
+
```
|
99
|
+
|
100
|
+
5. Archiving or unarchiving a list:
|
101
|
+
```ruby
|
102
|
+
list = Cakemail::List.find(list_id)
|
103
|
+
list.archive
|
104
|
+
# List is archived
|
105
|
+
list.unarchive
|
106
|
+
# List is unarchived
|
107
|
+
```
|
108
|
+
|
109
|
+
## Handling large data sets
|
110
|
+
|
111
|
+
The `find_in_batches` method, similar to its counterpart in ActiveRecord, allows you to retrieve records from a collection in batches. This is useful when dealing with large datasets, as it helps overcome API limitations by retrieving data in batches of 50, rather than loading the entire collection into memory at once.
|
112
|
+
|
113
|
+
Here's an example of how to use `find_in_batches` in the Cakemail Ruby Gem:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
Cakemail::List.find_in_batches do |list|
|
117
|
+
puts list
|
118
|
+
end
|
119
|
+
```
|
120
|
+
|
121
|
+
## Contacts
|
122
|
+
|
123
|
+
Here are some common use cases for managing contacts:
|
124
|
+
|
125
|
+
1. Retrieve all contacts in a list
|
126
|
+
|
127
|
+
To retrieve all contacts in a given list, you can use the `list` method of the `Cakemail::Contact` class. Make sure to specify the parent list when calling the method:
|
128
|
+
|
129
|
+
```ruby
|
130
|
+
# Get lists
|
131
|
+
lists = Cakemail::List.all
|
132
|
+
|
133
|
+
# Retrieve all contacts in a list
|
134
|
+
contacts = Cakemail::Contact.list(parent: lists.first)
|
135
|
+
|
136
|
+
contacts.each do |contact|
|
137
|
+
puts "Email: #{contact.email}"
|
138
|
+
puts "Status: #{contact.status}"
|
139
|
+
puts "Subscription Date: #{Time.at(contact.subscribed_on)}"
|
140
|
+
puts "---"
|
141
|
+
end
|
142
|
+
|
143
|
+
# Or directly from a list object
|
144
|
+
lists.first.contacts
|
145
|
+
```
|
146
|
+
|
147
|
+
2. Create a new contact
|
148
|
+
|
149
|
+
To create a new contact in a specific list, use the `create` method of the `Cakemail::Contact` class. Provide the necessary information, such as the email address, as a parameter hash:
|
150
|
+
|
151
|
+
```ruby
|
152
|
+
# Create a new contact
|
153
|
+
params = {
|
154
|
+
email: "nathan.lopez042@gmail.com"
|
155
|
+
}
|
156
|
+
|
157
|
+
new_contact = Cakemail::Contact.create(params, parent: list)
|
158
|
+
|
159
|
+
puts "Contact created successfully."
|
160
|
+
puts "Email: #{new_contact.email}"
|
161
|
+
puts "Status: #{new_contact.status}"
|
162
|
+
|
163
|
+
# Or create from list
|
164
|
+
|
165
|
+
new_contact = list.create_contact(params)
|
166
|
+
puts "Contact created successfully."
|
167
|
+
```
|
168
|
+
|
169
|
+
3. Updating an existing contact:
|
170
|
+
```ruby
|
171
|
+
list = Cakemail::List.find(list_id)
|
172
|
+
contact = list.contacts.last
|
173
|
+
|
174
|
+
contact.update(email: "new_mail@gmail.com")
|
175
|
+
puts "Updated contact email: #{contact.email}"
|
176
|
+
```
|
177
|
+
|
178
|
+
4. Deleting a contact:
|
179
|
+
```ruby
|
180
|
+
list = Cakemail::List.find(list_id)
|
181
|
+
contact = list.contacts.last
|
182
|
+
|
183
|
+
contact.delete
|
184
|
+
puts "Contact deleted successfully."
|
185
|
+
```
|
186
|
+
|
187
|
+
5. Unsubscribe a contact:
|
188
|
+
```ruby
|
189
|
+
list = Cakemail::List.find(list_id)
|
190
|
+
contact = list.contacts.last
|
191
|
+
|
192
|
+
contact.unsubscribe
|
193
|
+
puts "Contact unsubscribed successfully."
|
194
|
+
```
|
data/Rakefile
ADDED
data/cakemail.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/cakemail/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "cakemail-next-gen"
|
7
|
+
spec.version = Cakemail::VERSION
|
8
|
+
spec.authors = ["Nathan Lopez"]
|
9
|
+
spec.email = ["nathan.lopez042@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "This library allows you to quickly and easily use the Cakemail Next-gen API via Ruby."
|
12
|
+
spec.description = "This library allows you to quickly and easily use the Cakemail Next-gen API via Ruby."
|
13
|
+
spec.homepage = "https://github.com/andrewdsilva/cakemail-ruby"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/andrewdsilva/cakemail-ruby"
|
19
|
+
|
20
|
+
spec.files = Dir.chdir(__dir__) do
|
21
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
22
|
+
(File.expand_path(f) == __FILE__) ||
|
23
|
+
f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor Gemfile])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
spec.bindir = "exe"
|
27
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = ["lib"]
|
29
|
+
end
|
data/images/logo.png
ADDED
Binary file
|
@@ -0,0 +1,248 @@
|
|
1
|
+
module Cakemail
|
2
|
+
# @attr [Integer] id Id of the list
|
3
|
+
class Base
|
4
|
+
class NoParentError < StandardError; end
|
5
|
+
|
6
|
+
attr_accessor :id, :parent
|
7
|
+
|
8
|
+
# Returns Cakemail object with id and type provided
|
9
|
+
#
|
10
|
+
# @param id [String]
|
11
|
+
# @return [List, Contact, Campaign, Tags]
|
12
|
+
#
|
13
|
+
# @example
|
14
|
+
# list = Cakemail::List.find(1)
|
15
|
+
# list.class #=> Cakemail::User
|
16
|
+
# list.id #=> 1
|
17
|
+
def self.find(id, options = {})
|
18
|
+
parent = get_parent(options)
|
19
|
+
|
20
|
+
path = "#{object_class.path}/#{id}"
|
21
|
+
path = path_with_parent(path, parent) if parent
|
22
|
+
|
23
|
+
response = Cakemail.get path
|
24
|
+
|
25
|
+
instantiate_object response["data"] unless response.nil?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns Cakemail objects
|
29
|
+
#
|
30
|
+
# @param page [Integer]
|
31
|
+
# @param per_page [Integer]
|
32
|
+
# @return [Array<List>, Array<Contact>, Array<Campaign>, Array<Tags>]
|
33
|
+
#
|
34
|
+
# @example
|
35
|
+
# contacts = Cakemail::Contact.list(1, 50)
|
36
|
+
def self.list(options = {})
|
37
|
+
page = options[:page] || 1
|
38
|
+
per_page = options[:per_page] || 50
|
39
|
+
filters = options[:filters] || {}
|
40
|
+
parent = options[:parent] || nil
|
41
|
+
|
42
|
+
no_parent_exception if parent_required && parent.nil?
|
43
|
+
|
44
|
+
path = "#{object_class.path}?page=#{page}&per_page=#{per_page}"
|
45
|
+
path = path_with_parent(path, parent) if parent
|
46
|
+
|
47
|
+
unless filters.keys.empty?
|
48
|
+
query = filters.map { |key, value| "filter=#{key}==#{value}" }.join("&")
|
49
|
+
|
50
|
+
path += "&#{query}"
|
51
|
+
end
|
52
|
+
|
53
|
+
response = Cakemail.get path
|
54
|
+
|
55
|
+
instantiate_object_list(response["data"], parent) unless response.nil?
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns total count
|
59
|
+
#
|
60
|
+
# @return Integer
|
61
|
+
#
|
62
|
+
# @example
|
63
|
+
# total_contacts = Cakemail::Contact.count
|
64
|
+
def self.count(options = {})
|
65
|
+
parent = get_parent(options)
|
66
|
+
|
67
|
+
path = "#{object_class.path}?page=1&per_page=1&with_count=true"
|
68
|
+
path = path_with_parent(path, parent) if parent
|
69
|
+
|
70
|
+
response = Cakemail.get path
|
71
|
+
|
72
|
+
response["pagination"]["count"] unless response.nil?
|
73
|
+
end
|
74
|
+
|
75
|
+
# Yields each batch of records that was found
|
76
|
+
#
|
77
|
+
# @param block [Block]
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# total_contacts = Cakemail::Contact.count
|
81
|
+
def self.find_in_batches(options = {}, &block)
|
82
|
+
total = count(options)
|
83
|
+
|
84
|
+
per_page = options[:per_page] || 50
|
85
|
+
page = 1
|
86
|
+
|
87
|
+
loop do
|
88
|
+
list(options.merge(page: page, per_page: per_page)).each do |object|
|
89
|
+
block.call(object)
|
90
|
+
end
|
91
|
+
|
92
|
+
break if page * per_page > total
|
93
|
+
|
94
|
+
page += 1
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Create a new object and return it
|
99
|
+
#
|
100
|
+
# @param params [Hash]
|
101
|
+
# @return [List, Contact, Campaign, Tags]
|
102
|
+
#
|
103
|
+
# @example
|
104
|
+
# my_list = Cakemail::List.create(name: "My list")
|
105
|
+
def self.create(params, options = {})
|
106
|
+
parent = get_parent(options)
|
107
|
+
|
108
|
+
no_parent_exception if parent_required && parent.nil?
|
109
|
+
|
110
|
+
path = object_class.path
|
111
|
+
path = path_with_parent(path, parent) if parent
|
112
|
+
|
113
|
+
response = Cakemail.post path, params.to_json
|
114
|
+
|
115
|
+
return response unless response_ok? response
|
116
|
+
|
117
|
+
instantiate_object(response["data"]) unless response.nil?
|
118
|
+
end
|
119
|
+
|
120
|
+
# Delete Cakemail object
|
121
|
+
#
|
122
|
+
# @return Boolean
|
123
|
+
#
|
124
|
+
# @example
|
125
|
+
# list = Cakemail::List.find(1)
|
126
|
+
# list.delete
|
127
|
+
def delete(options = {})
|
128
|
+
parent = get_parent(options)
|
129
|
+
|
130
|
+
path = "#{self.class.object_class.path}/#{id}"
|
131
|
+
path = self.class.path_with_parent(path, parent) if parent
|
132
|
+
|
133
|
+
response = Cakemail.delete path
|
134
|
+
|
135
|
+
self.class.response_ok?(response) && response["deleted"]
|
136
|
+
end
|
137
|
+
|
138
|
+
# Update Cakemail object and return it
|
139
|
+
#
|
140
|
+
# @return [List, Contact, Campaign, Tags]
|
141
|
+
#
|
142
|
+
# @example
|
143
|
+
# list = Cakemail::List.find(1)
|
144
|
+
# list.update(name: "My list 2")
|
145
|
+
def update(params, options = {})
|
146
|
+
parent = get_parent(options)
|
147
|
+
|
148
|
+
path = "#{self.class.object_class.path}/#{id}"
|
149
|
+
path = self.class.path_with_parent(path, parent) if parent
|
150
|
+
|
151
|
+
response = Cakemail.patch path, params.to_json
|
152
|
+
|
153
|
+
return response unless self.class.response_ok?(response) && response["updated"]
|
154
|
+
|
155
|
+
self.class.instantiate_object(response["data"]) unless response.nil?
|
156
|
+
end
|
157
|
+
|
158
|
+
# Archive Cakemail object and return it
|
159
|
+
#
|
160
|
+
# @return [List, Contact, Campaign, Tags]
|
161
|
+
#
|
162
|
+
# @example
|
163
|
+
# list = Cakemail::List.find(1)
|
164
|
+
# list.archive
|
165
|
+
def archive(options = {})
|
166
|
+
parent = get_parent(options)
|
167
|
+
|
168
|
+
path = "#{self.class.object_class.path}/#{id}/archive"
|
169
|
+
path = self.class.path_with_parent(path, parent) if parent
|
170
|
+
|
171
|
+
response = Cakemail.post path, {}.to_json
|
172
|
+
|
173
|
+
return response unless self.class.response_ok?(response) && response["archived"]
|
174
|
+
|
175
|
+
self.class.instantiate_object(response) unless response.nil?
|
176
|
+
end
|
177
|
+
|
178
|
+
# Unarchive Cakemail object and return it
|
179
|
+
#
|
180
|
+
# @return [List, Contact, Campaign, Tags]
|
181
|
+
#
|
182
|
+
# @example
|
183
|
+
# list = Cakemail::List.find(1)
|
184
|
+
# list.unarchive
|
185
|
+
def unarchive(options = {})
|
186
|
+
parent = get_parent(options)
|
187
|
+
|
188
|
+
path = "#{self.class.object_class.path}/#{id}/unarchive"
|
189
|
+
path = self.class.path_with_parent(path, parent) if parent
|
190
|
+
|
191
|
+
response = Cakemail.post path, {}.to_json
|
192
|
+
|
193
|
+
return response unless self.class.response_ok?(response) && !response["archive"]
|
194
|
+
|
195
|
+
self.class.instantiate_object(response) unless response.nil?
|
196
|
+
end
|
197
|
+
|
198
|
+
def self.get_parent(options = {})
|
199
|
+
options[:parent] || nil
|
200
|
+
end
|
201
|
+
|
202
|
+
def get_parent(options = {})
|
203
|
+
@parent || self.class.get_parent(options)
|
204
|
+
end
|
205
|
+
|
206
|
+
def self.no_parent_exception
|
207
|
+
raise NoParentError
|
208
|
+
end
|
209
|
+
|
210
|
+
def self.parent_required
|
211
|
+
false
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.path_with_parent(path, parent)
|
215
|
+
"#{parent.class.path}/#{parent.id}/#{path}"
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.response_ok?(response)
|
219
|
+
[200, 201].include?(response["status_code"])
|
220
|
+
end
|
221
|
+
|
222
|
+
def initialize(options = {})
|
223
|
+
@id = options["id"]
|
224
|
+
end
|
225
|
+
|
226
|
+
def self.object_class; end
|
227
|
+
|
228
|
+
def self.instantiate_object_list(json, parent = nil)
|
229
|
+
json.map { |json_object| instantiate_object(json_object, parent) }
|
230
|
+
end
|
231
|
+
|
232
|
+
def self.instantiate_object(json, parent = nil)
|
233
|
+
object = object_class.new json
|
234
|
+
|
235
|
+
object.parent = parent unless parent.nil?
|
236
|
+
|
237
|
+
object
|
238
|
+
end
|
239
|
+
|
240
|
+
def respond_to?(method_name)
|
241
|
+
attr = "@#{method_name}"
|
242
|
+
|
243
|
+
return super if method_name.match(/[?!]$/) || !instance_variable_defined?(attr)
|
244
|
+
|
245
|
+
true
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require "dotenv/load"
|
2
|
+
|
3
|
+
module Cakemail
|
4
|
+
module Configuration
|
5
|
+
def self.api_key
|
6
|
+
@api_key
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.api_key=(api_key)
|
10
|
+
@api_key = api_key
|
11
|
+
end
|
12
|
+
|
13
|
+
DEFAULT = {
|
14
|
+
api_key: ENV["CAKEMAIL_API_KEY"]
|
15
|
+
}.freeze
|
16
|
+
|
17
|
+
DEFAULT.each do |param, default_value|
|
18
|
+
send("#{param}=", default_value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require "dotenv/load"
|
2
|
+
require "faraday"
|
3
|
+
|
4
|
+
module Cakemail
|
5
|
+
class MissingAuthentication < StandardError; end
|
6
|
+
class JsonResponseError < StandardError; end
|
7
|
+
|
8
|
+
API_URI = "https://api.cakemail.dev".freeze
|
9
|
+
VERBS = %w[get post patch delete].freeze
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :raw_response
|
13
|
+
|
14
|
+
VERBS.each do |verb|
|
15
|
+
define_method verb do |path, params = {}, headers = {}|
|
16
|
+
send_request(verb, path, params, headers)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def api_key
|
21
|
+
Cakemail.config.api_key
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def parse_json(json)
|
27
|
+
JSON.parse(json)
|
28
|
+
rescue
|
29
|
+
raise JsonResponseError
|
30
|
+
end
|
31
|
+
|
32
|
+
def missing_authentication?(response)
|
33
|
+
parse_json(response.body)&.dig("detail") == "Not authenticated"
|
34
|
+
end
|
35
|
+
|
36
|
+
def auth_header
|
37
|
+
headers = { "accept" => "application/json", "Content-Type" => "application/json" }
|
38
|
+
headers = headers.merge("authorization" => "Bearer #{api_key}") if api_key
|
39
|
+
|
40
|
+
headers
|
41
|
+
end
|
42
|
+
|
43
|
+
def send_request(http_verb, path, params, headers)
|
44
|
+
connection = Faraday.new(url: API_URI)
|
45
|
+
response = connection.send(http_verb.downcase.to_sym, path, params, auth_header.merge(headers))
|
46
|
+
|
47
|
+
raise MissingAuthentication if missing_authentication? response
|
48
|
+
|
49
|
+
parse_json(response.body).merge("status_code" => response.status)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|