emarsys 0.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 (59) hide show
  1. data/.gitignore +18 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +11 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +171 -0
  6. data/Rakefile +7 -0
  7. data/emarsys.gemspec +25 -0
  8. data/lib/emarsys.rb +60 -0
  9. data/lib/emarsys/client.rb +40 -0
  10. data/lib/emarsys/data_object.rb +78 -0
  11. data/lib/emarsys/data_objects/condition.rb +20 -0
  12. data/lib/emarsys/data_objects/contact.rb +121 -0
  13. data/lib/emarsys/data_objects/contact_list.rb +47 -0
  14. data/lib/emarsys/data_objects/email.rb +133 -0
  15. data/lib/emarsys/data_objects/email_category.rb +20 -0
  16. data/lib/emarsys/data_objects/email_launch_status.rb +38 -0
  17. data/lib/emarsys/data_objects/email_status_code.rb +39 -0
  18. data/lib/emarsys/data_objects/event.rb +44 -0
  19. data/lib/emarsys/data_objects/export.rb +22 -0
  20. data/lib/emarsys/data_objects/field.rb +39 -0
  21. data/lib/emarsys/data_objects/file.rb +39 -0
  22. data/lib/emarsys/data_objects/folder.rb +24 -0
  23. data/lib/emarsys/data_objects/form.rb +21 -0
  24. data/lib/emarsys/data_objects/language.rb +20 -0
  25. data/lib/emarsys/data_objects/segment.rb +21 -0
  26. data/lib/emarsys/data_objects/source.rb +40 -0
  27. data/lib/emarsys/error.rb +24 -0
  28. data/lib/emarsys/extensions.rb +8 -0
  29. data/lib/emarsys/field_mapping.rb +55 -0
  30. data/lib/emarsys/params_converter.rb +29 -0
  31. data/lib/emarsys/request.rb +46 -0
  32. data/lib/emarsys/response.rb +24 -0
  33. data/lib/emarsys/version.rb +3 -0
  34. data/spec/emarsys/client_spec.rb +85 -0
  35. data/spec/emarsys/data_object_spec.rb +55 -0
  36. data/spec/emarsys/data_objects/condition_spec.rb +9 -0
  37. data/spec/emarsys/data_objects/contact_list_spec.rb +9 -0
  38. data/spec/emarsys/data_objects/contact_spec.rb +79 -0
  39. data/spec/emarsys/data_objects/email_category_spec.rb +9 -0
  40. data/spec/emarsys/data_objects/email_launch_status_spec.rb +25 -0
  41. data/spec/emarsys/data_objects/email_spec.rb +84 -0
  42. data/spec/emarsys/data_objects/email_status_code_spec.rb +25 -0
  43. data/spec/emarsys/data_objects/event_spec.rb +23 -0
  44. data/spec/emarsys/data_objects/export_spec.rb +9 -0
  45. data/spec/emarsys/data_objects/field_spec.rb +19 -0
  46. data/spec/emarsys/data_objects/file_spec.rb +29 -0
  47. data/spec/emarsys/data_objects/folder_spec.rb +13 -0
  48. data/spec/emarsys/data_objects/form_spec.rb +9 -0
  49. data/spec/emarsys/data_objects/language_spec.rb +9 -0
  50. data/spec/emarsys/data_objects/segment_spec.rb +9 -0
  51. data/spec/emarsys/data_objects/source_spec.rb +25 -0
  52. data/spec/emarsys/extensions_spec.rb +24 -0
  53. data/spec/emarsys/field_mapping_spec.rb +14 -0
  54. data/spec/emarsys/params_converter_spec.rb +52 -0
  55. data/spec/emarsys/request_spec.rb +27 -0
  56. data/spec/emarsys/response_spec.rb +35 -0
  57. data/spec/emarsys_spec.rb +22 -0
  58. data/spec/spec_helper.rb +28 -0
  59. metadata +178 -0
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in emarsys.gemspec
4
+
5
+ group :test do
6
+ gem 'rspec', '~> 2.13.0'
7
+ gem 'webmock', '~> 1.9.0'
8
+ end
9
+
10
+
11
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Daniel Schoppmann
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,171 @@
1
+ # emarsys-rb
2
+
3
+ Simple Ruby wrapper for the Emarsys API.
4
+
5
+ ## Installation
6
+
7
+ gem install emarsys
8
+
9
+ ## Emarsys API Hint
10
+
11
+ This wrapper tries to implement all available methods of the Emarsys API in a
12
+ Ruby-like fashion. However, the Emarsys API lacks a decent amount of methods that
13
+ you expect an API to provide.
14
+ Thus, if methods are missing or a certain implementation
15
+ style was choosen it is most likely due to the inconsistency of the API itself.
16
+ Feel free to get in touch or submit a pull request if you encounter any problems.
17
+
18
+ Must-known facts about the Emarsys API:
19
+
20
+ * Emarsys uses internal IDs as field identifiers. E.g. 'email' is mapped to the value 3.
21
+ This gem tries to work around this by letting you specify a field mapping constant.
22
+ * certain methods require the specification of a key-field, e.g. the email (internally refered to as '3' again).
23
+ * Return values differ from method to method due to the way the Emarsys API is implemented.
24
+ Thus, a Hash as a return value or an Array of Hashes was choosen as the global return object. Basically it is a parsed JSON response.
25
+ * Please refer to the Emarsys API documentation for detailed information on parameters, return values or error codes.
26
+
27
+ ## Configuration and Setup
28
+ ### Authentication
29
+
30
+ Authenticate with the api credentials provided by your Emarsys account manager.
31
+
32
+ Emarsys.configure do |c|
33
+ c.api_username = 'my_username'
34
+ c.api_password = 'my_password'
35
+ # OPTIONAL, defaults to https://suite5.emarsys.net/api/v2
36
+ c.api_endpoint = 'https://www.emarsys.net/api/v2'
37
+ end
38
+
39
+ ### Field Mapping
40
+
41
+ As said before, Emarsys loves IDs. For using an APi, they are evil. This Gem provides
42
+ an easy way to adjust the individual field settings. Internally a Ruby Mapping Constant is used,
43
+ which that can be overwritten. It will be picked up automatically. E.g.:
44
+
45
+ # Complete overwrite
46
+ Emarsys::FieldMapping::ATTRIBUTES = [
47
+ {:id => 0, :identifier => 'interests', :name => 'Interests'},
48
+ {:id => 1, :identifier => 'firstname', :name => 'First Name'},
49
+ {:id => 2, :identifier => 'lastname', :name => 'Last Name'},
50
+ ]
51
+
52
+ # Add to the Mapping-Constant
53
+ Emarsys::FieldMapping::ATTRIBUTES << {:id => 100, :identifier => 'user_id', :name => "User-ID"}
54
+
55
+ All Emarsys predefined system fields are prefixed with an underscore, e.g. '_firstname' or '_revenue' in order to not
56
+ clash with individual mappings.
57
+
58
+
59
+ ## Interacting with the API
60
+
61
+ You can interact with the API on the provided data objects:
62
+
63
+ #### Condition
64
+
65
+ # Get all conditions
66
+ Emarsys::Condition.collection
67
+
68
+ #### Contact
69
+
70
+ # Create a contact with custom key_field (one example with mapped identifier, one without)
71
+ Emarsys::Contact.create('user_id', 10, {firstname: "Jane", lastname: "Doe", email: "jane.doe@example.com"})
72
+ Emarsys::Contact.create(4980, 10, {1 => "Jane", 2 => "Doe", 3 => "jane.doe@example.com"})
73
+
74
+ # Update a contact with key_field (one example with mapped identifier, one without)
75
+ Emarsys::Contact.update('email', "jane.doe@example.com", {firstname: "John", lastname: "Doe"})
76
+ Emarsys::Contact.update(3, "jane.doe@example.com", {1 => "John", 2 => "Doe"})
77
+
78
+ #### ContactList
79
+
80
+ # Get all contact_lists
81
+ Emarsys::ContactList.collection
82
+
83
+ # Create a contact list
84
+ Emarsys::ContactList.create
85
+
86
+ #### Emails
87
+
88
+ # Get all email campaigns, optional filter
89
+ Emarsys::Email.collection
90
+ Emarsys::Email.collection(status: 3)
91
+
92
+ # Get a single email resource
93
+ Emarsys::Email.resource(1)
94
+
95
+ # Create a new email campaign
96
+ Emarsys::Email.create({})
97
+
98
+ Emarsys::Email.launch({})
99
+
100
+ #### Event
101
+
102
+ Emarsys::Event.collection
103
+
104
+ # Trigger a custom event
105
+ Emarsys::Event.trigger(65, 3, ["test@example.com"])
106
+
107
+ # Trigger a custom event which actually sends a mail
108
+ # (Emarsys way to send transactional mails with placeholders)
109
+ Emarsys::Event.trigger(2, 3, 'test@example.com', {:global => {:my_placeholder => "some content"}})
110
+
111
+ #### Export
112
+
113
+ Emarsys::Export.resource(1)
114
+
115
+ #### Field
116
+
117
+ Emarsys::Field.collection
118
+ Emarsys::Field.choice(1)
119
+
120
+ #### Folder
121
+
122
+ # Get all forms, optional filter parameters
123
+ Emarsys::Folder.collection
124
+ Emarsys::Folder.collection(:folder => 3)
125
+
126
+ #### Form
127
+
128
+ # Get all forms
129
+ Emarsys::Form.collection
130
+
131
+ #### Language
132
+
133
+ # Get all languages
134
+ Emarsys::Language.collection
135
+
136
+ #### Segment
137
+
138
+ # Get all segments
139
+ Emarsys::Segment.collection
140
+
141
+ #### Source
142
+
143
+ # Get all sources
144
+ Emarsys::Source.collection
145
+
146
+ # Create a new source
147
+ Emarsys::Source.create("New Source")
148
+
149
+ # Destroy a source
150
+ Emarsys::Source.destroy(123)
151
+
152
+
153
+ Please refer to the code for detailed instructions of each method.
154
+
155
+ ## Ruby Versions
156
+
157
+ This gem was developed and tested with versions 1.9.3 and 2.0.0
158
+
159
+
160
+ ## Contributing
161
+
162
+ 1. Fork it
163
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
164
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
165
+ 4. Push to the branch (`git push origin my-new-feature`)
166
+ 5. Create new Pull Request
167
+
168
+
169
+ ## Copyright
170
+
171
+ Copyright (c) 2013 Daniel Schoppmann. See LICENSE.txt for details.
data/Rakefile ADDED
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rspec/core/rake_task'
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :test => :spec
7
+ task :default => :spec
data/emarsys.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'emarsys/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "emarsys"
8
+ spec.version = Emarsys::VERSION
9
+ spec.authors = ["Daniel Schoppmann"]
10
+ spec.email = ["daniel.schoppmann@absolventa.de"]
11
+ spec.description = %q{A Ruby library for interacting with the Emarsys API.}
12
+ spec.summary = %q{Easy to use ruby library for Emarsys Marketing Suite.}
13
+ spec.homepage = "http://www.absolventa.de"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rest-client"
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.3"
24
+ spec.add_development_dependency "rake"
25
+ end
data/lib/emarsys.rb ADDED
@@ -0,0 +1,60 @@
1
+ require "base64"
2
+ require 'json'
3
+ require 'rest_client'
4
+ require 'uri'
5
+
6
+ require 'emarsys/client'
7
+ require 'emarsys/data_object'
8
+ require 'emarsys/error'
9
+ require 'emarsys/extensions'
10
+ require 'emarsys/field_mapping'
11
+ require 'emarsys/params_converter'
12
+ require 'emarsys/request'
13
+ require 'emarsys/response'
14
+
15
+ require 'emarsys/data_objects/condition'
16
+ require 'emarsys/data_objects/contact_list'
17
+ require 'emarsys/data_objects/contact'
18
+ require 'emarsys/data_objects/email'
19
+ require 'emarsys/data_objects/email_category'
20
+ require 'emarsys/data_objects/email_launch_status'
21
+ require 'emarsys/data_objects/email_status_code'
22
+ require 'emarsys/data_objects/event'
23
+ require 'emarsys/data_objects/export'
24
+ require 'emarsys/data_objects/field'
25
+ require 'emarsys/data_objects/file'
26
+ require 'emarsys/data_objects/folder'
27
+ require 'emarsys/data_objects/form'
28
+ require 'emarsys/data_objects/language'
29
+ require 'emarsys/data_objects/segment'
30
+ require 'emarsys/data_objects/source'
31
+
32
+ require "emarsys/version"
33
+
34
+ # Ruby toolkit for the Emarsys API
35
+ module Emarsys
36
+ class << self
37
+
38
+ # @!attribute api_endpoint
39
+ # @return [String] Base URL for emarsys URLs. default: https://suite5.emarsys.net/api/v2
40
+ # @!attribute api_password
41
+ # @return [String] API Username given by Emarsys
42
+ # @!attribute api_username
43
+ # @return [String] API Username given by Emarsys
44
+
45
+ attr_accessor :api_endpoint, :api_username, :api_password
46
+
47
+ # Base URL for the Emarsys API
48
+ #
49
+ # @return [String] domain which should be used to query the API
50
+ def api_endpoint
51
+ @api_endpoint ||= 'https://suite5.emarsys.net/api/v2'
52
+ end
53
+
54
+ # Set configuration options using a block
55
+ def configure
56
+ yield self
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,40 @@
1
+ module Emarsys
2
+ class Client
3
+
4
+ def username
5
+ raise ArgumentError, "Emarsys.api_username is not set" if Emarsys.api_username.nil?
6
+ Emarsys.api_username
7
+ end
8
+
9
+ def password
10
+ raise ArgumentError, "Emarsys.api_password is not set" if Emarsys.api_password.nil?
11
+ Emarsys.api_password
12
+ end
13
+
14
+ def x_wsse_string
15
+ string = 'UsernameToken '
16
+ string += 'Username = "' + username + '", '
17
+ string += 'PasswordDigest = "' + header_password_digest + '", '
18
+ string += 'Nonce = "' + header_nonce + '", '
19
+ string += 'Created = "' + header_created + '"'
20
+ string
21
+ end
22
+
23
+ def header_password_digest
24
+ Base64.encode64(calculated_digest).gsub("\n", "")
25
+ end
26
+
27
+ def header_nonce
28
+ Digest::MD5.hexdigest(Time.new.to_i.to_s)
29
+ end
30
+
31
+ def header_created
32
+ Time.new.strftime("%Y-%m-%d %H:%M:%S")
33
+ end
34
+
35
+ def calculated_digest
36
+ Digest::SHA1.hexdigest(header_nonce + header_created + password)
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,78 @@
1
+ #require 'hashie'
2
+
3
+ module Emarsys
4
+ class DataObject
5
+ class << self
6
+
7
+ # Make a HTTP GET request
8
+ #
9
+ # @param method_name [String] The path, relative to Emarsys.api_endpoint
10
+ # @param params [Hash] custom params hash
11
+ # @return [Hash]
12
+ def get(method_name, params)
13
+ if params.empty?
14
+ self.new.request 'get', method_name, params
15
+ else
16
+ self.new.request 'get', [method_name, parameterize_params(params)].join("/"), {}
17
+ end
18
+ end
19
+
20
+ # Make a HTTP POST request
21
+ #
22
+ # @param method_name [String] The path, relative to Emarsys.api_endpoint
23
+ # @param params [Hash] custom params hash
24
+ # @return [Hash]
25
+ def post(method_name, params)
26
+ self.new.request 'post', method_name, params
27
+ end
28
+
29
+ # Make a HTTP PUT request
30
+ #
31
+ # @param method_name [String] The path, relative to Emarsys.api_endpoint
32
+ # @param params [Hash] custom params hash
33
+ # @return [Hash]
34
+ def put(method_name, params)
35
+ self.new.request 'put', method_name, params
36
+ end
37
+
38
+ # Make a HTTP DELETE request
39
+ #
40
+ # @param method_name [String] The path, relative to Emarsys.api_endpoint
41
+ # @param params [Hash] custom params hash
42
+ # @return [Hash]
43
+ def delete(method_name, params)
44
+ self.new.request 'delete', method_name, params
45
+ end
46
+
47
+ # Custom Parameterizer for Emarsys
48
+ #
49
+ # @param params [Hash] custom params hash
50
+ # @return [String] key => value is returned as key=value
51
+ def parameterize_params(params)
52
+ params.inject(""){|string, (k, v)| string << "#{k}=#{v}"; string << "&"; string}[0..-2]
53
+ end
54
+ end
55
+
56
+ # Make a HTTP request
57
+ #
58
+ # @param http_verb [String] Http method
59
+ # @param method_name [String] The path, relative to Emarsys.api_endpoint
60
+ # @param params [Hash] custom params hash
61
+ # @return [Hash]
62
+ def request(http_verb, method_name, params)
63
+ response = Emarsys::Request.new(http_verb, method_name, params).send_request
64
+ #hashiefy(response)
65
+ end
66
+
67
+ # TODO: Not finally evaluated. Is Hashie necessary? Maybe use "real Data Objects instead"?
68
+ # def hashiefy(response)
69
+ # if response.is_a?(Array)
70
+ # response.map!{|elem| Hashie::Mash.new(elem) }
71
+ # elsif
72
+ # Hashie::Mash.new(response)
73
+ # else
74
+ # response
75
+ # end
76
+ # end
77
+ end
78
+ end