mail2cb 0.0.6
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/.gitignore +23 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/LICENSE.txt +22 -0
- data/README.md +51 -0
- data/Rakefile +2 -0
- data/bin/mail2cb +16 -0
- data/config.yml +27 -0
- data/lib/mail2cb/email_body_parser.rb +28 -0
- data/lib/mail2cb/email_handler.rb +113 -0
- data/lib/mail2cb/email_watcher.rb +126 -0
- data/lib/mail2cb/encryption.rb +42 -0
- data/lib/mail2cb/helpers.rb +16 -0
- data/lib/mail2cb/version.rb +3 -0
- data/lib/mail2cb.rb +33 -0
- data/lib/public/custom.css +19 -0
- data/lib/public/dashboard.css +105 -0
- data/lib/server.rb +6 -0
- data/lib/views/settings.erb +113 -0
- data/lib/views/stats.erb +100 -0
- data/mail2cb.gemspec +35 -0
- data/test/lib/order2cb/order_test.rb +20 -0
- data/test/lib/order2cb/version_test.rb +7 -0
- data/test/lib/order2cb_test.rb +25 -0
- data/test/test_helper.rb +3 -0
- metadata +230 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 33aab03227466886d6226040f67f9fae5e3e6257
|
4
|
+
data.tar.gz: fc394d4cf8701deb082584652ef5000f9f76a5eb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8aa7c084a6643350703598e925ab60763f8d495b80770eb49ce4bd975f15c79ab584e0b8fc4f2c5f024ec22e49b524faf9861aa11c312dfb52366f27afa07daa
|
7
|
+
data.tar.gz: e5d63b2a62b9c42d5e13832e64ab0ad5c5b5cf141ae99497e07dbe35efab2cdf656ef3a94a289166e09ea7973265cadec62d89f23a7f4e131629a2f44df603a9
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
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
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
23
|
+
*.swp
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mail2cb
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.2.3
|
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 EmergeAdapt
|
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.
|
22
|
+
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Ijonas Kisselbach
|
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,51 @@
|
|
1
|
+
# mail2cb
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'mail2cb'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install mail2cb
|
18
|
+
|
19
|
+
## Design
|
20
|
+
|
21
|
+
###Gems
|
22
|
+
|
23
|
+
* mail_room - retrieves mail from multiple mailboxes at once and sends them through sidekiq or an http postback
|
24
|
+
* mail - mail parsing and sending gem
|
25
|
+
* talon - python code to extract the relevant body of the message
|
26
|
+
|
27
|
+
|
28
|
+
### Notes
|
29
|
+
|
30
|
+
* config for office365 smtp needs authentication type 'login' gmail is 'plain'
|
31
|
+
* gmail apps authentication is by ip address only, suggest a feature of being able to host the send daemon on another box
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Ensure the following environment variables are set:
|
36
|
+
|
37
|
+
REDIS_URL=redis://localhost:6379
|
38
|
+
CB_API_ENDPOINT=https://login.caseblocks.com
|
39
|
+
CB_API_TOKEN=...
|
40
|
+
|
41
|
+
And run the daemon from the CLI
|
42
|
+
|
43
|
+
mail2cb
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
1. Fork it ( https://github.com/[my-github-username]/mail2cb/fork )
|
48
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
49
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
50
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
51
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/bin/mail2cb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby -Ilib
|
2
|
+
require 'rubygems'
|
3
|
+
require 'bundler/setup'
|
4
|
+
# Prepares the $LOAD_PATH by adding to it lib directories of the gem and
|
5
|
+
# its dependencies:
|
6
|
+
require 'mail2cb'
|
7
|
+
|
8
|
+
ENV["REDIS_URL"] = "redis://localhost:6379" unless ENV["REDIS_URL"]
|
9
|
+
ENV["MYSQL_HOST"] = "localhost" unless ENV["MYSQL_HOST"]
|
10
|
+
ENV["MYSQL_PORT"] = "3306"
|
11
|
+
ENV["MYSQL_DATABASE"] = "caseblocks_dev"
|
12
|
+
|
13
|
+
ENV["MYSQL_USERNAME"] = "root"
|
14
|
+
ENV["MYSQL_PASSWORD"] = ""
|
15
|
+
|
16
|
+
oh = Mail2cb::Handler.new
|
data/config.yml
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
---
|
2
|
+
:mailboxes:
|
3
|
+
-
|
4
|
+
:email: "stewart@activeinformationdesign.com"
|
5
|
+
:password: "junction1"
|
6
|
+
:name: "inbox"
|
7
|
+
:search_command: 'UNSEEN'
|
8
|
+
:delivery_method: sidekiq
|
9
|
+
:delivery_options:
|
10
|
+
:worker: EmailHandlerWorker
|
11
|
+
-
|
12
|
+
:email: "stewart@emergeadapt.com"
|
13
|
+
:password: "junction1"
|
14
|
+
:name: "inbox"
|
15
|
+
:search_command: 'UNSEEN'
|
16
|
+
:delivery_method: sidekiq
|
17
|
+
:delivery_options:
|
18
|
+
:worker: EmailHandlerWorker
|
19
|
+
-
|
20
|
+
:email: "stewartmckee@emergeadapttest.onmicrosoft.com"
|
21
|
+
:host: "outlook.office365.com"
|
22
|
+
:password: "Katr1n33"
|
23
|
+
:name: "inbox"
|
24
|
+
:search_command: 'UNSEEN'
|
25
|
+
:delivery_method: sidekiq
|
26
|
+
:delivery_options:
|
27
|
+
:worker: EmailHandlerWorker
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Mail2cb
|
4
|
+
class EmailBodyParser
|
5
|
+
def self.parse(text, type="text/plain")
|
6
|
+
|
7
|
+
data_hash = {:body => text, :type => type}
|
8
|
+
|
9
|
+
json_hash = data_hash.to_json
|
10
|
+
|
11
|
+
stdin, stdout, stderr, wait_thr = Open3.popen3('python', '/Users/stewartmckee/code/talon/test.py')
|
12
|
+
stdin.write(json_hash)
|
13
|
+
stdin.close
|
14
|
+
result = stdout.read
|
15
|
+
stdout.close
|
16
|
+
error = stderr.read
|
17
|
+
stderr.close
|
18
|
+
exit_code = wait_thr.value
|
19
|
+
if exit_code == 0
|
20
|
+
result
|
21
|
+
else
|
22
|
+
puts result
|
23
|
+
raise error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'mail'
|
3
|
+
require_relative "email_body_parser"
|
4
|
+
require 'nokogiri'
|
5
|
+
require 'sanitize'
|
6
|
+
|
7
|
+
module Mail2cb
|
8
|
+
class EmailHandler
|
9
|
+
def initialize(options)
|
10
|
+
@options = options
|
11
|
+
@email = Mail.read_from_string(options[:inbound_message])
|
12
|
+
|
13
|
+
puts "Handling inbound email from #{@email.from}"
|
14
|
+
|
15
|
+
if @email.multipart?
|
16
|
+
@email.parts.each do |part|
|
17
|
+
content_type = part.content_type.split(";")[0]
|
18
|
+
if content_type[0..3] == "text"
|
19
|
+
if content_type == "text/html"
|
20
|
+
@html_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
21
|
+
elsif content_type == "text/plain"
|
22
|
+
@text_body = part.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
else
|
27
|
+
@text_body = @email.body.decoded.force_encoding("ASCII-8BIT").encode('UTF-8', undef: :replace, replace: '')
|
28
|
+
end
|
29
|
+
|
30
|
+
@body = @html_body || @text_body
|
31
|
+
end
|
32
|
+
|
33
|
+
def generate_message_hash
|
34
|
+
|
35
|
+
message_hash = {
|
36
|
+
"from" => @email.from,
|
37
|
+
"to" => @email.to,
|
38
|
+
"subject" => @email.subject,
|
39
|
+
"date" => @email.date,
|
40
|
+
"body" => @body,
|
41
|
+
"attachements" => prepare_attachments,
|
42
|
+
"metadata" => fetch_metadata
|
43
|
+
}
|
44
|
+
message_hash.delete(:inbound_message)
|
45
|
+
message_hash
|
46
|
+
end
|
47
|
+
|
48
|
+
def fetch_metadata
|
49
|
+
fetch_fingerprints.merge({
|
50
|
+
"has_bounced" => @email.bounced?,
|
51
|
+
"in_reply_to" => @email.in_reply_to,
|
52
|
+
"message_id" => @email.message_id,
|
53
|
+
"references" => references
|
54
|
+
})
|
55
|
+
end
|
56
|
+
|
57
|
+
def references
|
58
|
+
@email.header["References"] ? @email.header["References"].field.element.message_ids : []
|
59
|
+
end
|
60
|
+
|
61
|
+
def fetch_fingerprints
|
62
|
+
previous_id = references.last
|
63
|
+
match = /(.*?)\.(.*?)@emergeadapt.com/.match(previous_id)
|
64
|
+
if match
|
65
|
+
if match[2] == "case"
|
66
|
+
{"case_id" => match[1]}
|
67
|
+
else
|
68
|
+
{"message_id" => match[1]}
|
69
|
+
end
|
70
|
+
else
|
71
|
+
{}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def prepare_attachments
|
76
|
+
attachments = []
|
77
|
+
@email.attachments.each do | attachment |
|
78
|
+
filename = attachment.filename
|
79
|
+
random_tag = Random.rand(100000000000)
|
80
|
+
attachment_folder = File.join(["/", "tmp", "caseblocks", @options[:mailbox][:account_code], "attachments"])
|
81
|
+
FileUtils::mkdir_p(attachment_folder)
|
82
|
+
file_path = File.join([attachment_folder, "#{random_tag}.#{filename}"])
|
83
|
+
File.open(file_path, "w+b", 0644) {|f| f.write attachment.body.decoded}
|
84
|
+
attachments << {
|
85
|
+
"filename" => attachment.filename,
|
86
|
+
"filepath" => file_path
|
87
|
+
}
|
88
|
+
end
|
89
|
+
attachments
|
90
|
+
end
|
91
|
+
|
92
|
+
|
93
|
+
def content_type
|
94
|
+
@html_body.nil? ? "text/plain" : "text/html"
|
95
|
+
end
|
96
|
+
|
97
|
+
def sanitize!
|
98
|
+
@body = Sanitize.fragment(@body, Sanitize::Config::RELAXED)
|
99
|
+
end
|
100
|
+
|
101
|
+
def clean_replies!
|
102
|
+
@body = Mail2cb::EmailBodyParser.parse(@body, content_type)
|
103
|
+
end
|
104
|
+
|
105
|
+
def queue!
|
106
|
+
$redis
|
107
|
+
end
|
108
|
+
|
109
|
+
def body
|
110
|
+
@body
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'ap'
|
3
|
+
require 'mysql2'
|
4
|
+
|
5
|
+
module Mail2cb
|
6
|
+
class EmailWatcher
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
|
10
|
+
raise "REDIS_URL environment variable is required (eg redis://localhost:6739)" unless ENV["REDIS_URL"]
|
11
|
+
raise "MYSQL_HOST environment variable is required" unless ENV["MYSQL_HOST"]
|
12
|
+
raise "MYSQL_DATABASE environment variable is required" unless ENV["MYSQL_DATABASE"]
|
13
|
+
raise "MYSQL_USERNAME environment variable is required" unless ENV["MYSQL_USERNAME"]
|
14
|
+
raise "MYSQL_PASSWORD environment variable is required" unless ENV["MYSQL_PASSWORD"]
|
15
|
+
|
16
|
+
ENV["MYSQL_PASSWORD"] = "" unless ENV["MYSQL_PASSWORD"]
|
17
|
+
ENV["MYSQL_PORT"] = "3306"
|
18
|
+
|
19
|
+
redis_url = URI.parse(ENV["REDIS_URL"])
|
20
|
+
|
21
|
+
$redis = Redis.new(:host => redis_url.host, :port => redis_url.port)
|
22
|
+
|
23
|
+
Signal.trap("INT") {
|
24
|
+
Thread.new {self.stop}.join
|
25
|
+
}
|
26
|
+
# Trap `Kill `
|
27
|
+
Signal.trap("TERM") {
|
28
|
+
Thread.new {self.stop}.join
|
29
|
+
}
|
30
|
+
|
31
|
+
@daemon = MailDaemon::Handler.new(:connections => configuration)
|
32
|
+
end
|
33
|
+
|
34
|
+
def start
|
35
|
+
Thread.new do
|
36
|
+
@daemon.start do |message, type|
|
37
|
+
if type == "status_update"
|
38
|
+
update_status(message)
|
39
|
+
else
|
40
|
+
handle_incoming_message(message)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def configuration
|
47
|
+
mailboxes = []
|
48
|
+
mysql_client do |mysql|
|
49
|
+
statement = mysql.prepare("SELECT case_blocks_email_accounts.id, case_blocks_accounts.nickname, case_blocks_email_accounts.imap_username, case_blocks_email_accounts.imap_encrypted_password, case_blocks_email_accounts.imap_host, case_blocks_email_accounts.imap_port, case_blocks_email_accounts.imap_ssl, case_blocks_email_accounts.imap_start_tls, case_blocks_email_accounts.imap_folder_name, case_blocks_email_accounts.imap_search_command, case_blocks_email_accounts.imap_messages_processed, case_blocks_email_accounts.imap_last_processed_at FROM case_blocks_email_accounts JOIN case_blocks_accounts ON case_blocks_email_accounts.account_id = case_blocks_accounts.id where imap_enabled=1")
|
50
|
+
result = statement.execute()
|
51
|
+
result.each do |row|
|
52
|
+
ssl_options = row["imap_ssl"]==1 ? {:verify_mode => OpenSSL::SSL::VERIFY_NONE} : false
|
53
|
+
decrypted_password = Encryption.new.decrypt(row["imap_encrypted_password"])
|
54
|
+
mailboxes << {:id => row["id"], :account_code => row["nickname"], :username => row["imap_username"], :host => row["imap_host"], :port => row["imap_port"], :password => decrypted_password, :ssl_options => ssl_options, :start_tls => row["imap_start_tls"]==1, :name => row["imap_folder_nam"], :search_command => row["imap_search_command"], :message_count => row["imap_messages_processed"], :last_delivered_at => row["imap_last_processed_at"]}
|
55
|
+
end
|
56
|
+
end
|
57
|
+
mailboxes
|
58
|
+
end
|
59
|
+
|
60
|
+
def restart
|
61
|
+
@daemon.reload(:connections => configuration)
|
62
|
+
end
|
63
|
+
|
64
|
+
def handle_incoming_message(options)
|
65
|
+
@handler = Mail2cb::EmailHandler.new(options)
|
66
|
+
@handler.sanitize!
|
67
|
+
# @handler.clean_replies!
|
68
|
+
|
69
|
+
hash = @handler.generate_message_hash
|
70
|
+
|
71
|
+
$redis.lpush(redis_key(options), hash)
|
72
|
+
puts "Queued."
|
73
|
+
end
|
74
|
+
|
75
|
+
def redis_key(options)
|
76
|
+
"cb:comms:#{options[:mailbox][:account_code]}:inbox"
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_status(options)
|
80
|
+
puts "Status Update: #{options[:status]} for #{options[:mailbox][:username]}"
|
81
|
+
mysql_client do |mysql|
|
82
|
+
status_message = options[:status]
|
83
|
+
statement = mysql.prepare("UPDATE case_blocks_email_accounts SET imap_status='#{options[:status]}', imap_status_message='#{status_message}' where id=?")
|
84
|
+
statement.execute(options[:mailbox][:id])
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def mysql_client(&block)
|
91
|
+
client = Mysql2::Client.new(:host => ENV["MYSQL_HOST"], :port => ENV["MYSQL_PORT"], :username => ENV["MYSQL_USERNAME"], :password => ENV["MYSQL_PASSWORD"], :database => ENV["MYSQL_DATABASE"])
|
92
|
+
yield client
|
93
|
+
client.close
|
94
|
+
end
|
95
|
+
|
96
|
+
def mailbox_status_message(watcher)
|
97
|
+
if watcher.logging_in?
|
98
|
+
"Connecting and Logging into server"
|
99
|
+
elsif watcher.logged_in?
|
100
|
+
"Connected"
|
101
|
+
else
|
102
|
+
"Disconnected"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
def mailbox_status(watcher)
|
106
|
+
if watcher.logging_in?
|
107
|
+
:logging_in
|
108
|
+
elsif watcher.logged_in?
|
109
|
+
:connected
|
110
|
+
else
|
111
|
+
:disconnected
|
112
|
+
end
|
113
|
+
end
|
114
|
+
def mailbox_status_colour(watcher)
|
115
|
+
if watcher.logging_in?
|
116
|
+
"orange"
|
117
|
+
elsif watcher.logged_in?
|
118
|
+
"green"
|
119
|
+
else
|
120
|
+
"red"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Mail2cb
|
4
|
+
class Encryption
|
5
|
+
|
6
|
+
def initialize()
|
7
|
+
@key = ENV["CASEBLOCKS_ENCRYPTION_KEY"] || "YLX0IBT+OXaO4mP2bVYqzMPbrrss8eUcX1XtgLxlVH8="
|
8
|
+
@iv = ENV["CASEBLOCKS_ENCRYPTION_IV"] || "vvSVfoWvZQ3T/DfjsjO/9w=="
|
9
|
+
end
|
10
|
+
|
11
|
+
def encrypt(data)
|
12
|
+
unless data.nil?
|
13
|
+
cipher = OpenSSL::Cipher::AES.new(128, :CBC)
|
14
|
+
cipher.encrypt
|
15
|
+
cipher.key = Base64.decode64(@key)
|
16
|
+
cipher.iv = Base64.decode64(@iv)
|
17
|
+
encrypted = cipher.update(data) + cipher.final
|
18
|
+
|
19
|
+
# [0..-2] strip off trailing carriage return
|
20
|
+
Base64.encode64(encrypted)[0..-2]
|
21
|
+
else
|
22
|
+
data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def decrypt(value)
|
27
|
+
unless value.nil?
|
28
|
+
decipher = OpenSSL::Cipher::AES.new(128, :CBC)
|
29
|
+
decipher.decrypt
|
30
|
+
decipher.key = Base64.decode64(@key)
|
31
|
+
decipher.iv = Base64.decode64(@iv)
|
32
|
+
|
33
|
+
encrypted = Base64.decode64(value)
|
34
|
+
decipher.update(encrypted) + decipher.final
|
35
|
+
else
|
36
|
+
value
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Mail2cb
|
2
|
+
module Helpers
|
3
|
+
def setup_options(options)
|
4
|
+
@options = options.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
|
5
|
+
end
|
6
|
+
def default_option(name, value)
|
7
|
+
@options[name.to_s.to_sym] = value unless @options.has_key?(name.to_s.to_sym)
|
8
|
+
end
|
9
|
+
def required_option(names)
|
10
|
+
names_array = Array(names)
|
11
|
+
names_array.each do |name|
|
12
|
+
raise "#{name} is a required option, please supply this in the call to new" unless @options.has_key?(name.to_s.to_sym)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/mail2cb.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
require_relative 'mail2cb/version'
|
2
|
+
require_relative 'mail2cb/helpers'
|
3
|
+
require_relative 'mail2cb/email_body_parser'
|
4
|
+
require_relative 'mail2cb/email_watcher'
|
5
|
+
require_relative 'mail2cb/email_handler'
|
6
|
+
require_relative 'mail2cb/encryption'
|
7
|
+
require 'sinatra/base'
|
8
|
+
require 'json'
|
9
|
+
require 'open3'
|
10
|
+
require 'mail'
|
11
|
+
require 'mail_daemon'
|
12
|
+
|
13
|
+
module Mail2cb
|
14
|
+
class Handler
|
15
|
+
def initialize
|
16
|
+
@@watcher = EmailWatcher.new
|
17
|
+
|
18
|
+
@@watcher.start
|
19
|
+
|
20
|
+
my_app = Sinatra.new do
|
21
|
+
set :logging, false
|
22
|
+
set :run, false
|
23
|
+
|
24
|
+
get('/reload') do
|
25
|
+
@@watcher.restart
|
26
|
+
"OK"
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
my_app.run!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.status-circle {
|
2
|
+
width: 10px;
|
3
|
+
height: 10px;
|
4
|
+
background-color: #ccc;
|
5
|
+
border-radius: 50%;
|
6
|
+
margin-top: 6px;
|
7
|
+
}
|
8
|
+
|
9
|
+
.status-circle.red {
|
10
|
+
background-color: red;
|
11
|
+
}
|
12
|
+
|
13
|
+
.status-circle.green {
|
14
|
+
background-color: green;
|
15
|
+
}
|
16
|
+
|
17
|
+
.status-circle.orange {
|
18
|
+
background-color: orange;
|
19
|
+
}
|
@@ -0,0 +1,105 @@
|
|
1
|
+
/*
|
2
|
+
* Base structure
|
3
|
+
*/
|
4
|
+
|
5
|
+
/* Move down content because we have a fixed navbar that is 50px tall */
|
6
|
+
body {
|
7
|
+
padding-top: 50px;
|
8
|
+
}
|
9
|
+
|
10
|
+
|
11
|
+
/*
|
12
|
+
* Global add-ons
|
13
|
+
*/
|
14
|
+
|
15
|
+
.sub-header {
|
16
|
+
padding-bottom: 10px;
|
17
|
+
border-bottom: 1px solid #eee;
|
18
|
+
}
|
19
|
+
|
20
|
+
/*
|
21
|
+
* Top navigation
|
22
|
+
* Hide default border to remove 1px line.
|
23
|
+
*/
|
24
|
+
.navbar-fixed-top {
|
25
|
+
border: 0;
|
26
|
+
}
|
27
|
+
|
28
|
+
/*
|
29
|
+
* Sidebar
|
30
|
+
*/
|
31
|
+
|
32
|
+
/* Hide for mobile, show later */
|
33
|
+
.sidebar {
|
34
|
+
display: none;
|
35
|
+
}
|
36
|
+
@media (min-width: 768px) {
|
37
|
+
.sidebar {
|
38
|
+
position: fixed;
|
39
|
+
top: 51px;
|
40
|
+
bottom: 0;
|
41
|
+
left: 0;
|
42
|
+
z-index: 1000;
|
43
|
+
display: block;
|
44
|
+
padding: 20px;
|
45
|
+
overflow-x: hidden;
|
46
|
+
overflow-y: auto; /* Scrollable contents if viewport is shorter than content. */
|
47
|
+
background-color: #f5f5f5;
|
48
|
+
border-right: 1px solid #eee;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
/* Sidebar navigation */
|
53
|
+
.nav-sidebar {
|
54
|
+
margin-right: -21px; /* 20px padding + 1px border */
|
55
|
+
margin-bottom: 20px;
|
56
|
+
margin-left: -20px;
|
57
|
+
}
|
58
|
+
.nav-sidebar > li > a {
|
59
|
+
padding-right: 20px;
|
60
|
+
padding-left: 20px;
|
61
|
+
}
|
62
|
+
.nav-sidebar > .active > a,
|
63
|
+
.nav-sidebar > .active > a:hover,
|
64
|
+
.nav-sidebar > .active > a:focus {
|
65
|
+
color: #fff;
|
66
|
+
background-color: #428bca;
|
67
|
+
}
|
68
|
+
|
69
|
+
|
70
|
+
/*
|
71
|
+
* Main content
|
72
|
+
*/
|
73
|
+
|
74
|
+
.main {
|
75
|
+
padding: 20px;
|
76
|
+
}
|
77
|
+
@media (min-width: 768px) {
|
78
|
+
.main {
|
79
|
+
padding-right: 40px;
|
80
|
+
padding-left: 40px;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
.main .page-header {
|
84
|
+
margin-top: 0;
|
85
|
+
}
|
86
|
+
|
87
|
+
|
88
|
+
/*
|
89
|
+
* Placeholder dashboard ideas
|
90
|
+
*/
|
91
|
+
|
92
|
+
.placeholders {
|
93
|
+
margin-bottom: 30px;
|
94
|
+
text-align: center;
|
95
|
+
}
|
96
|
+
.placeholders h4 {
|
97
|
+
margin-bottom: 0;
|
98
|
+
}
|
99
|
+
.placeholder {
|
100
|
+
margin-bottom: 20px;
|
101
|
+
}
|
102
|
+
.placeholder img {
|
103
|
+
display: inline-block;
|
104
|
+
border-radius: 50%;
|
105
|
+
}
|
data/lib/server.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
8
|
+
<title>CaseBlocks Email Watcher</title>
|
9
|
+
|
10
|
+
<!-- Bootstrap -->
|
11
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
12
|
+
<link href="dashboard.css" rel="stylesheet">
|
13
|
+
|
14
|
+
|
15
|
+
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
16
|
+
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
17
|
+
<!--[if lt IE 9]>
|
18
|
+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
19
|
+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
20
|
+
<![endif]-->
|
21
|
+
</head>
|
22
|
+
<body>
|
23
|
+
|
24
|
+
<nav class="navbar navbar-inverse navbar-fixed-top">
|
25
|
+
<div class="container-fluid">
|
26
|
+
<div class="navbar-header">
|
27
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
28
|
+
<span class="sr-only">Toggle navigation</span>
|
29
|
+
<span class="icon-bar"></span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
<span class="icon-bar"></span>
|
32
|
+
</button>
|
33
|
+
<a class="navbar-brand" href="#">CaseBlocks Email Watcher</a>
|
34
|
+
</div>
|
35
|
+
<div id="navbar" class="navbar-collapse collapse">
|
36
|
+
<ul class="nav navbar-nav navbar-right">
|
37
|
+
<li><a href="/">Dashboard</a></li>
|
38
|
+
<li><a href="/settings">Settings</a></li>
|
39
|
+
</ul>
|
40
|
+
<form class="navbar-form navbar-right">
|
41
|
+
<input type="text" class="form-control" placeholder="Search...">
|
42
|
+
</form>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</nav>
|
46
|
+
|
47
|
+
<div class="container-fluid">
|
48
|
+
<div class="row">
|
49
|
+
|
50
|
+
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
|
51
|
+
<h1 class="page-header">Dashboard</h1>
|
52
|
+
|
53
|
+
<div class="row placeholders">
|
54
|
+
<div class="col-xs-6 col-sm-3 placeholder">
|
55
|
+
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
|
56
|
+
<h4>Label</h4>
|
57
|
+
<span class="text-muted">Something else</span>
|
58
|
+
</div>
|
59
|
+
<div class="col-xs-6 col-sm-3 placeholder">
|
60
|
+
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
|
61
|
+
<h4>Label</h4>
|
62
|
+
<span class="text-muted">Something else</span>
|
63
|
+
</div>
|
64
|
+
<div class="col-xs-6 col-sm-3 placeholder">
|
65
|
+
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
|
66
|
+
<h4>Label</h4>
|
67
|
+
<span class="text-muted">Something else</span>
|
68
|
+
</div>
|
69
|
+
<div class="col-xs-6 col-sm-3 placeholder">
|
70
|
+
<img src="data:image/gif;base64,R0lGODlhAQABAIAAAHd3dwAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==" width="200" height="200" class="img-responsive" alt="Generic placeholder thumbnail">
|
71
|
+
<h4>Label</h4>
|
72
|
+
<span class="text-muted">Something else</span>
|
73
|
+
</div>
|
74
|
+
</div>
|
75
|
+
|
76
|
+
<h2 class="sub-header">Mailboxes</h2>
|
77
|
+
<div class="table-responsive">
|
78
|
+
<table class="table table-striped">
|
79
|
+
<thead>
|
80
|
+
<tr>
|
81
|
+
<th>Email Address</th>
|
82
|
+
<th>Host</th>
|
83
|
+
<th>Delivery Method</th>
|
84
|
+
</tr>
|
85
|
+
</thead>
|
86
|
+
<tbody>
|
87
|
+
<% @mailboxes.each do |mailbox| %>
|
88
|
+
<tr>
|
89
|
+
<td><%= mailbox[:email] %></td>
|
90
|
+
<td><%= mailbox[:host] %></td>
|
91
|
+
<td><%= mailbox[:delivery_method] %></td>
|
92
|
+
</tr>
|
93
|
+
<% end %>
|
94
|
+
</tbody>
|
95
|
+
</table>
|
96
|
+
</div>
|
97
|
+
</div>
|
98
|
+
</div>
|
99
|
+
</div>
|
100
|
+
|
101
|
+
<!-- Bootstrap core JavaScript
|
102
|
+
================================================== -->
|
103
|
+
<!-- Placed at the end of the document so the pages load faster -->
|
104
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
105
|
+
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
|
106
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
|
107
|
+
|
108
|
+
|
109
|
+
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
110
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
111
|
+
|
112
|
+
</body>
|
113
|
+
</html>
|
data/lib/views/stats.erb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
|
8
|
+
<title>CaseBlocks Email Watcher</title>
|
9
|
+
|
10
|
+
<!-- Bootstrap -->
|
11
|
+
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" integrity="sha384-1q8mTJOASx8j1Au+a5WDVnPi2lkFfwwEAa8hDDdjZlpLegxhjVME1fgjWPGmkzs7" crossorigin="anonymous">
|
12
|
+
<link href="dashboard.css" rel="stylesheet">
|
13
|
+
<link href="custom.css" rel="stylesheet">
|
14
|
+
|
15
|
+
|
16
|
+
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
|
17
|
+
<!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
|
18
|
+
<!--[if lt IE 9]>
|
19
|
+
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
|
20
|
+
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
|
21
|
+
<![endif]-->
|
22
|
+
</head>
|
23
|
+
<body>
|
24
|
+
|
25
|
+
<nav class="navbar navbar-inverse navbar-fixed-top">
|
26
|
+
<div class="container-fluid">
|
27
|
+
<div class="navbar-header">
|
28
|
+
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
|
29
|
+
<span class="sr-only">Toggle navigation</span>
|
30
|
+
<span class="icon-bar"></span>
|
31
|
+
<span class="icon-bar"></span>
|
32
|
+
<span class="icon-bar"></span>
|
33
|
+
</button>
|
34
|
+
<a class="navbar-brand" href="#">CaseBlocks Email Watcher</a>
|
35
|
+
</div>
|
36
|
+
<div id="navbar" class="navbar-collapse collapse">
|
37
|
+
<ul class="nav navbar-nav navbar-right">
|
38
|
+
<li><a href="/">Dashboard</a></li>
|
39
|
+
<li><a href="/reload">Reload Configuration</a></li>
|
40
|
+
</ul>
|
41
|
+
<form class="navbar-form navbar-right">
|
42
|
+
<input type="text" class="form-control" placeholder="Search...">
|
43
|
+
</form>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
</nav>
|
47
|
+
|
48
|
+
<div class="container-fluid">
|
49
|
+
<div class="row">
|
50
|
+
<div class="col-sm-9 col-md-10 main" style="width: 100%;">
|
51
|
+
<!-- <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> -->
|
52
|
+
|
53
|
+
<h2 class="sub-header">Mailboxes</h2>
|
54
|
+
<div class="table-responsive">
|
55
|
+
<table class="table table-striped">
|
56
|
+
<thead>
|
57
|
+
<tr>
|
58
|
+
<th></th>
|
59
|
+
<th>Email Address</th>
|
60
|
+
<th>Host</th>
|
61
|
+
<th>Port</th>
|
62
|
+
<th>SSL</th>
|
63
|
+
<th>Start TLS</th>
|
64
|
+
<th>Messages Processed</th>
|
65
|
+
<th>Last Processed At</th>
|
66
|
+
</tr>
|
67
|
+
</thead>
|
68
|
+
<tbody>
|
69
|
+
<% @mailboxes.each do |mailbox| %>
|
70
|
+
<tr>
|
71
|
+
<td><div class="status-circle <%=mailbox[:status_colour]%>"></td>
|
72
|
+
<td><%= mailbox[:email] %></td>
|
73
|
+
<td><%= mailbox[:host] %></td>
|
74
|
+
<td><%= mailbox[:port] %></td>
|
75
|
+
<td><%= !!mailbox[:ssl] ? "Yes" : "No" %></td>
|
76
|
+
<td><%= mailbox[:start_tls] ? "Yes" : "No" %></td>
|
77
|
+
<td><%= mailbox[:message_count] %></td>
|
78
|
+
<td><%= mailbox[:last_delivered_at] %></td>
|
79
|
+
</tr>
|
80
|
+
<% end %>
|
81
|
+
</tbody>
|
82
|
+
</table>
|
83
|
+
</div>
|
84
|
+
</div>
|
85
|
+
</div>
|
86
|
+
</div>
|
87
|
+
|
88
|
+
<!-- Bootstrap core JavaScript
|
89
|
+
================================================== -->
|
90
|
+
<!-- Placed at the end of the document so the pages load faster -->
|
91
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
92
|
+
<script>window.jQuery || document.write('<script src="../../assets/js/vendor/jquery.min.js"><\/script>')</script>
|
93
|
+
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js" integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS" crossorigin="anonymous"></script>
|
94
|
+
|
95
|
+
|
96
|
+
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
97
|
+
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
|
98
|
+
|
99
|
+
</body>
|
100
|
+
</html>
|
data/mail2cb.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mail2cb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "mail2cb"
|
8
|
+
spec.version = Mail2cb::VERSION
|
9
|
+
spec.authors = ["EmergeAdapt"]
|
10
|
+
spec.email = ["development@emergeadapt.com"]
|
11
|
+
spec.summary = %q{Grabs orders from Tyreshopper and posts them to SQS.}
|
12
|
+
spec.description = %q{Basic WIP.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
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.6"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "awesome_print"
|
24
|
+
|
25
|
+
spec.add_dependency 'mysql2'
|
26
|
+
spec.add_dependency 'sidekiq'
|
27
|
+
spec.add_dependency 'mail'
|
28
|
+
spec.add_dependency 'mail_daemon', "~> 0.0.6"
|
29
|
+
spec.add_dependency 'charlock_holmes' # required for sidekiq delivery
|
30
|
+
spec.add_dependency 'nokogiri'
|
31
|
+
spec.add_dependency 'sinatra'
|
32
|
+
spec.add_dependency 'sanitize'
|
33
|
+
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
|
3
|
+
class TestOrder < Minitest::Test
|
4
|
+
def setup
|
5
|
+
@sample = {}
|
6
|
+
@order = Order.new(@sample)
|
7
|
+
end
|
8
|
+
|
9
|
+
def test_that_kitty_can_eat
|
10
|
+
assert_equal "OHAI!", @meme.i_can_has_cheezburger?
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_that_it_will_not_blend
|
14
|
+
refute_match /^no/i, @meme.will_it_blend?
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_that_will_be_skipped
|
18
|
+
skip "test this later"
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative '../test_helper'
|
2
|
+
|
3
|
+
class MessageHandlerTest < MiniTest::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
ENV['CB_API_ENDPOINT'] = 'https://cb.local/'
|
6
|
+
ENV['CB_API_TOKEN'] = '1234'
|
7
|
+
end
|
8
|
+
def test_invalid_construction
|
9
|
+
ENV['AWS_ACCESS_KEY'] = nil
|
10
|
+
ENV['AWS_SECRET_ACCESS_KEY'] = nil
|
11
|
+
ENV['CB_API_ENDPOINT'] = nil
|
12
|
+
ENV['CB_API_TOKEN'] = nil
|
13
|
+
assert_raises(RuntimeError) { mail2cb::OrderHandler.new }
|
14
|
+
end
|
15
|
+
def test_valid_construction
|
16
|
+
ENV['AWS_ACCESS_KEY'] = 'access'
|
17
|
+
ENV['AWS_SECRET_ACCESS_KEY'] = 'secret'
|
18
|
+
refute_nil mail2cb::OrderHandler.new
|
19
|
+
end
|
20
|
+
def test_basic_sqs_connectivity
|
21
|
+
oh = mail2cb::OrderHandler.new
|
22
|
+
result = oh.send_orders
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,230 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mail2cb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.6
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- EmergeAdapt
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-04-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: awesome_print
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: mysql2
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sidekiq
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: mail
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: mail_daemon
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 0.0.6
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 0.0.6
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: charlock_holmes
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :runtime
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: nokogiri
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :runtime
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: sinatra
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: sanitize
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
167
|
+
description: Basic WIP.
|
168
|
+
email:
|
169
|
+
- development@emergeadapt.com
|
170
|
+
executables:
|
171
|
+
- mail2cb
|
172
|
+
extensions: []
|
173
|
+
extra_rdoc_files: []
|
174
|
+
files:
|
175
|
+
- ".gitignore"
|
176
|
+
- ".ruby-gemset"
|
177
|
+
- ".ruby-version"
|
178
|
+
- Gemfile
|
179
|
+
- LICENSE
|
180
|
+
- LICENSE.txt
|
181
|
+
- README.md
|
182
|
+
- Rakefile
|
183
|
+
- bin/mail2cb
|
184
|
+
- config.yml
|
185
|
+
- lib/mail2cb.rb
|
186
|
+
- lib/mail2cb/email_body_parser.rb
|
187
|
+
- lib/mail2cb/email_handler.rb
|
188
|
+
- lib/mail2cb/email_watcher.rb
|
189
|
+
- lib/mail2cb/encryption.rb
|
190
|
+
- lib/mail2cb/helpers.rb
|
191
|
+
- lib/mail2cb/version.rb
|
192
|
+
- lib/public/custom.css
|
193
|
+
- lib/public/dashboard.css
|
194
|
+
- lib/server.rb
|
195
|
+
- lib/views/settings.erb
|
196
|
+
- lib/views/stats.erb
|
197
|
+
- mail2cb.gemspec
|
198
|
+
- test/lib/order2cb/order_test.rb
|
199
|
+
- test/lib/order2cb/version_test.rb
|
200
|
+
- test/lib/order2cb_test.rb
|
201
|
+
- test/test_helper.rb
|
202
|
+
homepage: ''
|
203
|
+
licenses:
|
204
|
+
- MIT
|
205
|
+
metadata: {}
|
206
|
+
post_install_message:
|
207
|
+
rdoc_options: []
|
208
|
+
require_paths:
|
209
|
+
- lib
|
210
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
211
|
+
requirements:
|
212
|
+
- - ">="
|
213
|
+
- !ruby/object:Gem::Version
|
214
|
+
version: '0'
|
215
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
|
+
requirements:
|
217
|
+
- - ">="
|
218
|
+
- !ruby/object:Gem::Version
|
219
|
+
version: '0'
|
220
|
+
requirements: []
|
221
|
+
rubyforge_project:
|
222
|
+
rubygems_version: 2.4.5.1
|
223
|
+
signing_key:
|
224
|
+
specification_version: 4
|
225
|
+
summary: Grabs orders from Tyreshopper and posts them to SQS.
|
226
|
+
test_files:
|
227
|
+
- test/lib/order2cb/order_test.rb
|
228
|
+
- test/lib/order2cb/version_test.rb
|
229
|
+
- test/lib/order2cb_test.rb
|
230
|
+
- test/test_helper.rb
|