rack-deduce-ingest 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 92c703107085e3dc141c2d612613ec728fd9478c
4
+ data.tar.gz: 8266ed0df3c04529f199f8befb3cfcb50690a801
5
+ SHA512:
6
+ metadata.gz: b7fcc373308d4257eea3873a3d730e2dfa7d3a3df078940fa7d573cc807cfc97ec5c0eff6c14d029f73809ded755d7cf4037e93a4014a988015ac5b3963108d9
7
+ data.tar.gz: dbb86d40fc0ab16b52b88d4d52204f131acb20018666ebc814903e1c51664e4bb96395a0789af1fcbded6f6e49a56f95f5c57618bb27e892d7666f27d8ce074b
@@ -0,0 +1,17 @@
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
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rack-deduce-ingest.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Solve Media Inc.
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.
@@ -0,0 +1,82 @@
1
+ # Rack::Deduce::Ingest
2
+
3
+ Rack middleware for Deduce's data ingestion API.
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rack-deduce-ingest'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rack-deduce-ingest
18
+
19
+ ## Usage
20
+
21
+ ### Configuration
22
+
23
+ `Rack::Deduce::Ingest` requires a Site ID and apikey, provided by Deduce. If you
24
+ have not been given one, please contact Deduce for more information.
25
+
26
+ #### Rails
27
+
28
+ A Railtie is included in this gem which will load the middleware automatically.
29
+ You will need to set the middleware parameters in your app configuration:
30
+
31
+ ```ruby
32
+ config.deduce_ingest.site_id = "your site id here"
33
+ config.deduce_ingest.apikey = "your apikey here"
34
+ ```
35
+
36
+ #### Sinatra, etc.
37
+
38
+ ```ruby
39
+ use Rack::Deduce::Ingest, "your site id here", { :ssl => false }
40
+ helpers Rack::Deduce::Ingest::Helpers
41
+ ```
42
+
43
+ ### Sending Data to Deduce
44
+
45
+ Within your view, use the helper +deduce_ingest_html+ to include the Javascript
46
+ collection code.
47
+
48
+ ```ruby
49
+ deduce_ingest_html("user@example.com")
50
+ ```
51
+
52
+ You may send an options hash if you need to override any of the configuration
53
+ options.
54
+
55
+ ```ruby
56
+ deduce_ingest_html("user@example.com", ssl: false)
57
+ ```
58
+
59
+ For a Rails site, be sure to mark the output as html safe.
60
+
61
+ ### Sending Events to Deduce
62
+
63
+ Within your controller, use the helper +deduce_event_post+ to notify Deduce of events.
64
+
65
+ ```ruby
66
+ deduce_event_post('marzelize', "user@example.com")
67
+ ```
68
+
69
+ Depending on the event type, additional data be send by passing an additional hash.
70
+ You should consult with Deduce support for specific parameters and event types.
71
+
72
+ ```ruby
73
+ deduce_event_post('marzelize', "user@example.com", {weather: 'cloudy'})
74
+ ```
75
+
76
+
77
+ ### Best Practices
78
+
79
+ * Only pass information that you have already verified to be valid.
80
+
81
+ * Work closely with your Deduce support representative.
82
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ require 'rack/deduce/ingest'
2
+ require 'rack/deduce/ingest/railtie' if defined?(Rails::Railtie)
@@ -0,0 +1,215 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ # Copyright (c) 2019
3
+ # Author: Tyler Cunnion
4
+ # Created: 2019-May-08 17:14 (EDT)
5
+ # Function: Deduce Ingest API
6
+
7
+ require "rack/deduce/ingest/version"
8
+ require "rack/deduce/ingest/helpers"
9
+
10
+ require 'json'
11
+ require 'digest'
12
+ require 'net/http'
13
+ require 'openssl'
14
+
15
+ module Rack
16
+ module Deduce
17
+ class Ingest
18
+
19
+ URL = "//lore.deduce.com/p/collect"
20
+ EVENT_URL = "https://event.deduce.com/p/event" # only https
21
+ TIMEOUT = 1.1
22
+ VERHASH = Digest::SHA1.hexdigest("ruby/#{VERSION}")[0..16]
23
+
24
+ class << self
25
+ attr_accessor :site_id, :apikey, :ssl, :testmode
26
+
27
+ # @param [String] site_id The site ID provided to you by Deduce
28
+ # @param [String] apikey The apikey provided to you by Deduce
29
+ # @param [Hash] options
30
+ # @option options [Boolean] :ssl (true) Use SSL?
31
+ def init(app, site_id, apikey, options = {})
32
+ @app = app
33
+
34
+ self.site_id = site_id
35
+ self.apikey = apikey
36
+ self.ssl = options[:ssl]
37
+ self.testmode = options[:testmode]
38
+ self.ssl = ssl
39
+ end
40
+
41
+ def html(email, options = {})
42
+
43
+ site_id = options[:site_id] || @site_id
44
+ use_ssl = @ssl
45
+ use_ssl = options[:ssl] if options.include? :ssl
46
+
47
+ user_data = {site: site_id, vers: VERHASH}
48
+ user_data[:testmode] = true if options[:testmode] || @testmode
49
+
50
+ if email_valid?(email)
51
+ email = email.strip
52
+ email_lc = email.downcase
53
+ email_uc = email.upcase
54
+ user_data[:ehls1] = Digest::SHA1.hexdigest(email_lc)
55
+ user_data[:ehus1] = Digest::SHA1.hexdigest(email_uc)
56
+ user_data[:ehlm5] = Digest::MD5.hexdigest(email_lc)
57
+ user_data[:ehum5] = Digest::MD5.hexdigest(email_uc)
58
+ user_data[:ehls2] = Digest::SHA256.hexdigest(email_lc)
59
+ user_data[:ehus2] = Digest::SHA256.hexdigest(email_uc)
60
+ end
61
+
62
+ url = options[:url]
63
+
64
+ if !url
65
+ if use_ssl.nil?
66
+ url = URL
67
+ elsif use_ssl
68
+ url = 'https:' + URL
69
+ else
70
+ url = 'http:' + URL
71
+ end
72
+ end
73
+
74
+ html = <<EOS
75
+ <script type="text/javascript">
76
+ var dd_info = #{JSON.pretty_generate(user_data)};
77
+ </script>
78
+ <script type="text/javascript" src="#{url}" async></script>
79
+ EOS
80
+
81
+ return html
82
+ end
83
+
84
+ # @param [Array] event data
85
+ # @param [Hash] options
86
+ # @return [String] on error, returns an error message; or nothing on success
87
+ def events(evts, options = {})
88
+ return if limited?
89
+
90
+ site_id = @site_id
91
+ apikey = @apikey
92
+ timeout = options[:timeout] || (TIMEOUT + evts.length / 10)
93
+
94
+ post_data = { site: site_id, apikey: apikey, vers: VERHASH }
95
+ post_data[:backfill] = true if options[:backfill]
96
+ post_data[:testmode] = true if options[:testmode] || @testmode
97
+ post_data[:events] = evts.map{ |e| fixup_event( e.dup ) }
98
+
99
+ uri = URI(options[:url] || EVENT_URL)
100
+ http = Net::HTTP.new(uri.host, uri.port)
101
+
102
+ http.use_ssl = (uri.scheme == 'https')
103
+ http.open_timeout = timeout
104
+ http.read_timeout = timeout
105
+ http.ssl_timeout = timeout
106
+
107
+ hreq = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
108
+ hreq.body = post_data.to_json
109
+
110
+ p post_data.to_json
111
+
112
+ begin
113
+ res = http.request(hreq)
114
+ if res.code != '200'
115
+ raise "#{res.code} - #{res.body}"
116
+ end
117
+ rescue => e
118
+ adjust_fail
119
+ return e
120
+ end
121
+ adjust_ok
122
+ # return nil on success, else return the error
123
+ return nil
124
+ end
125
+
126
+ # @param [String] email The user's email address
127
+ # @param [String] ip The user's ip address
128
+ # @param [String] event The event type
129
+ # @param [Hash] additional Additional data to send
130
+ # @param [Hash] options
131
+ # @return [String] on error, returns an error message; or nothing on success
132
+ def event(email, ip, event, additional = {}, options = {})
133
+ return if limited?
134
+ return "invalid email" unless email_valid? email
135
+
136
+ event_data = additional.dup
137
+ event_data[:email] = email # fixup will hash the email
138
+ event_data[:ip] = ip
139
+ event_data[:event] = event
140
+
141
+ events [event_data], options
142
+ end
143
+
144
+ ################
145
+ private
146
+
147
+ def email_valid?(email)
148
+ return unless email
149
+ return if email.nil? || email.empty?
150
+ return email.match /.+@.+/
151
+ end
152
+
153
+ def fixup_event(evt)
154
+ # send the hash of the email, not the actual email
155
+ email = evt[:email]
156
+
157
+ if email_valid? email
158
+ email = email.strip.downcase
159
+ evt[:ehls1] = Digest::SHA1.hexdigest(email)
160
+ unless evt.has_key? :email_provider
161
+ # pass in an empty value for email_provider to not send
162
+ evt[:email_provider] = email.split(/@/)[1]
163
+ end
164
+ evt.delete :email
165
+ end
166
+
167
+ if email_valid? evt[:email_prev]
168
+ evt[:ehls1_prev] = Digest::SHA1.hexdigest(evt[:email_prev].strip.downcase)
169
+ evt.delete :email_prev
170
+ end
171
+
172
+ # hash + remove any CC
173
+ if evt[:cc]
174
+ cc = evt[:cc].gsub /[^0-9]/, ''
175
+ evt[:ccs1] = Digest::SHA1.hexdigest(cc)
176
+ evt.delete :cc
177
+ end
178
+ return evt
179
+ end
180
+
181
+ # if the event post is failing - slow down
182
+ def adjust_ok
183
+ @limit -= 5.0
184
+ @limit = 0.0 if @limit < 0.0
185
+ end
186
+ def adjust_fail
187
+ @limit = (9 * @limit + 100.0) / 10
188
+ @limit = 100.0 if @limit > 100.0
189
+ end
190
+ def limited?
191
+ now = Time.now
192
+ @limit ||= 0.0
193
+ @lastt ||= now
194
+ dt = now - @lastt
195
+ @lastt = now
196
+ @limit *= 0.999 ** dt
197
+ Random.rand(100.0) < @limit
198
+ end
199
+
200
+ end
201
+
202
+ # @param [String] site_id The site ID provided to you by Deduce
203
+ # @param [String] apikey The apikey provided to you by Deduce
204
+ # @param [Hash] options
205
+ # @option options [Boolean] :ssl (true) Use SSL?
206
+ def initialize(app, site_id, apikey, options = {})
207
+ self.class.init(app, site_id, apikey, options)
208
+ self.class
209
+ end
210
+
211
+ end
212
+ end
213
+ end
214
+
215
+
@@ -0,0 +1,46 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ # Copyright (c) 2019
3
+ # Author: Tyler Cunnion
4
+ # Created: 2019-May-08 17:14 (EDT)
5
+ # Function: Deduce Ingest API
6
+
7
+
8
+ module Rack
9
+ module Deduce
10
+ class Ingest
11
+ module Helpers
12
+
13
+ # Outputs the Deduce ingest Javascript code. A cookie is
14
+ # set indicating the user has been collected from
15
+ #
16
+ # As this helper outputs HTML tags, when used in Rails it must be
17
+ # marked HTML safe before being written to the page.
18
+ #
19
+ # @param [String] email The user's email address
20
+ # @param [Hash] options
21
+ # @option options [String] :site_id
22
+ # @option options [Boolean] :ssl
23
+ def deduce_ingest_html(email, options = {})
24
+ Rack::Deduce::Ingest.html email, options
25
+ end
26
+
27
+ # Sends an event to Deduce
28
+ #
29
+ # @param [String] event The event type
30
+ # @param [String] email The user's email address
31
+ # @param [Hash] additional
32
+ # @param [Hash] options
33
+ def deduce_event_post(event, email, additional = {}, options = {})
34
+ additional[:session_id] = session.id unless additional.has_key? :session_id
35
+ additional[:url] ||= request.original_url
36
+ additional[:user_agent] ||= request.headers['User-Agent']
37
+
38
+ html = Rack::Deduce::Ingest.event email, request.remote_ip, event, additional, options
39
+ html = html.html_safe if html.respond_to :html_safe
40
+ html
41
+ end
42
+
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,33 @@
1
+ # -*- mode: ruby; coding: utf-8 -*-
2
+ # Copyright (c) 2019
3
+ # Author: Tyler Cunnion
4
+ # Created: 2019-May-08 17:14 (EDT)
5
+ # Function: Deduce Ingest API
6
+
7
+ module Rack
8
+ module Deduce
9
+ class Ingest::Railtie < Rails::Railtie
10
+ config.deduce_ingest = ActiveSupport::OrderedOptions.new
11
+
12
+ initializer "rack.deduce.ingest.initializer" do |app|
13
+ site_id = app.config.deduce_ingest[:site_id]
14
+ apikey = app.config.deduce_ingest[:apikey]
15
+ ssl = app.config.deduce_ingest[:ssl]
16
+
17
+ raise "A unique site identifier is required to use the deduce ingest API.\nContact Deduce (http://www.deduce.com) if you do not have one." unless site_id && apikey
18
+
19
+ options = {}
20
+ options[:ssl] = ssl
21
+ options[:testmode] = app.config.deduce_ingest[:testmode]
22
+
23
+ Rack::Deduce::Ingest.new app, site_id, apikey, options
24
+ end
25
+
26
+ initializer "rack.deduce.ingest.helpers" do
27
+ ActionView::Base.send :include, Rack::Deduce::Ingest::Helpers
28
+ ActionController::Base.send :include, Rack::Deduce::Ingest::Helpers
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ module Rack
2
+ module Deduce
3
+ class Ingest
4
+ VERSION = "0.0.1"
5
+ end
6
+ end
7
+ end
@@ -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 'rack/deduce/ingest/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rack-deduce-ingest"
8
+ spec.version = Rack::Deduce::Ingest::VERSION
9
+ spec.authors = ["Tyler Cunnion", "Jeff Weisberg"]
10
+ spec.email = ["support@deduce.com"]
11
+ spec.description = %q{Deduce Ingest API}
12
+ spec.summary = %q{Rack middleware for Deduce's Ingest API}
13
+ spec.homepage = ""
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_development_dependency "bundler", "~> 1.3"
22
+ spec.add_development_dependency "rake"
23
+
24
+ spec.add_dependency 'multi_json', '~> 1.10'
25
+ end
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-deduce-ingest
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Tyler Cunnion
8
+ - Jeff Weisberg
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-10-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: rake
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: multi_json
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '1.10'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '1.10'
56
+ description: Deduce Ingest API
57
+ email:
58
+ - support@deduce.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - lib/rack-deduce-ingest.rb
69
+ - lib/rack/deduce/ingest.rb
70
+ - lib/rack/deduce/ingest/helpers.rb
71
+ - lib/rack/deduce/ingest/railtie.rb
72
+ - lib/rack/deduce/ingest/version.rb
73
+ - rack-deduce-ingest.gemspec
74
+ homepage: ''
75
+ licenses:
76
+ - MIT
77
+ metadata: {}
78
+ post_install_message:
79
+ rdoc_options: []
80
+ require_paths:
81
+ - lib
82
+ required_ruby_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ required_rubygems_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: '0'
92
+ requirements: []
93
+ rubyforge_project:
94
+ rubygems_version: 2.5.2.3
95
+ signing_key:
96
+ specification_version: 4
97
+ summary: Rack middleware for Deduce's Ingest API
98
+ test_files: []