talktome 0.2.0 → 1.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 2817b7e3a3e6d077e889d0d53ac368195785af09
4
- data.tar.gz: e5d9c60306e644301a1029739f16041f3b740be2
2
+ SHA256:
3
+ metadata.gz: c02c611e3628b2f56012103e2c8ae0a5bb600ee9e11a24a7c7acf748475c9380
4
+ data.tar.gz: f1dadedcddd3f434298359293ef656be2f14396c7d9dd8c597ea5db2bb7a138b
5
5
  SHA512:
6
- metadata.gz: 8cf1e843cfd0ce3187bc693889ed5baf7e0deeddff436cf483ec0af6f20f6698e5d91eea60717f990b270f274bddd1ff959e75a1dca8fc7e5ad7325873c31f56
7
- data.tar.gz: f312d5300c8eeacee34bd90097d61bd996246081b0400e013f59a63147a374719a59c904b3bd191481fc9d08e1417c5eebf266374931273a448e05b047ff0c8f
6
+ metadata.gz: 76e3843b6ec151090b9c88f26180a620d82bb737360fbb43b8f70f6f10d559401bf822f626cfde81c3edd43df253388ded9ca8761ce849c2af55262eb6e66503
7
+ data.tar.gz: 5f6558c21f2eeebd114a876232be0eb2c6dfdde84d7862d105c6da2400ee55d367f1428289e572a02c64fb5e8056e4e8999a9bb28de0b2af1199c1dd5613bc73
data/LICENSE.md CHANGED
@@ -1,22 +1,20 @@
1
- # The MIT Licence
1
+ Copyright (c) 2017-2021 - Enspirit SPRL (Bernard Lambeau)
2
2
 
3
- Copyright (c) 2017 - Enspirit SPRL (Bernard Lambeau)
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
4
10
 
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:
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
12
13
 
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.
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,3 +1,141 @@
1
1
  # Talktome - Talk to users easily
2
2
 
3
- ...
3
+ [![Build Status](https://travis-ci.com/enspirit/talktome.svg?branch=master)](https://travis-ci.com/enspirit/talktome)
4
+
5
+ Talktome helps talking to users (by email for now, but later we aim to add support
6
+ for various notification systems) easily. As a ruby gem to be used programmatically,
7
+ or as a docker container exposing web services (different use cases, see below).
8
+
9
+ ## Using Talktome programmatically
10
+
11
+ Using Talktome programmatically is useful to send transactional emails to users.
12
+
13
+ ```
14
+ require 'talktome'
15
+ CLIENT = Talktome::Client::Local.new(path_to_templates)
16
+
17
+ # later on
18
+ CLIENT.talktome(template_name, user, template_info, strategies)
19
+
20
+ # typically, the will send an email to foo@bar.com instantiating
21
+ # the email found in path_to_templates/hello/email.md and
22
+ # instantiated using mustache and markdown
23
+ CLIENT.talktome("hello", {email: 'foo@bar.com'}, {}, [:email])
24
+ ```
25
+
26
+ ## Using Talktome using the docker image
27
+
28
+ The docker image aims at supporting another category of use cases, such as providing
29
+ a reusable backend for contact forms.
30
+
31
+ ```
32
+ docker run \
33
+ -p4567:4567 \
34
+ -e TALKTOME_EMAIL_DEFAULT_FROM=info@mydomain.com
35
+ -e TALKTOME_EMAIL_DEFAULT_TO=support@mydomain.com
36
+ enspirit/talktome
37
+ ```
38
+
39
+ Send an contact-us email through the web api using curl, as follows:
40
+
41
+ ```
42
+ curl -XPOST \
43
+ -H'Content-Type: application/json' \
44
+ -d'{"reply_to": "someone@foo.bar", "message": "Hello"}' \
45
+ http://127.0.0.1:4567/contact-us/
46
+ ```
47
+
48
+ This web API does not allow specifying `from` and `to` as input data to avoid
49
+ exposing a way to send SPAM easily.
50
+
51
+ ### Overriding templates (and having more than one endpoint)
52
+
53
+ The default image comes with a single contact-us email template used by Enspirit.
54
+ Feel free to override it by providing one or more email templates.
55
+
56
+ You can mount a volume with email templates into `/app/templates/`, which will
57
+ be used for the available endpoints. For instance, the following `templates/`
58
+ folder will expose two endpoints with possibly different behaviors (according
59
+ to the templates themselves):
60
+
61
+ ```
62
+ templates/
63
+ contact-us/
64
+ email.md
65
+ report-issue/
66
+ email.md
67
+ ```
68
+
69
+ Two usual ways to do so in docker: commandline or Dockerfile. On commandline,
70
+ use the following option:
71
+
72
+ ```
73
+ -v ${PWD}/my-templates:/app/templates
74
+ ```
75
+
76
+ In a Dockerfile, add your templates:
77
+
78
+ ```
79
+ FROM enspirit/talktome
80
+
81
+ COPY ./templates /app/templates
82
+ ```
83
+
84
+ ## Configuring Talktome
85
+
86
+ The easiest way to configure Talktome is through environment variables. The following
87
+ ones are supported:
88
+
89
+ ```
90
+ TALKTOME_DEBUG when set enables the dumping of sent messages to ./tmp folder
91
+
92
+ TALKTOME_EMAIL_DELIVERY smtp, file or test (see ruby Mail library)
93
+ TALKTOME_EMAIL_DEFAULT_FROM default From: to use for email sending
94
+ TALKTOME_EMAIL_DEFAULT_REPLYTO default Reply-To: to use for email sending
95
+ TALKTOME_EMAIL_DEFAULT_TO default To: to use for email sending
96
+
97
+ TALKTOME_EMAIL_SUBJECT Set the subject of the default "contact us" email
98
+ TALKTOME_EMAIL_FOOTER Set the footer of the default "contact us" email
99
+
100
+ TALKTOME_LAYOUTS_FOLDER Set the folder to use for messaging layouts
101
+
102
+ TALKTOME_SMTP_ADDRESS host address for smtp sending
103
+ TALKTOME_SMTP_PORT port of smtp server to use
104
+ TALKTOME_SMTP_DOMAIN sending domain
105
+ TALKTOME_SMTP_USER user for smtp authentication
106
+ TALKTOME_SMTP_PASSWORD password for smtp authentication
107
+ TALKTOME_SMTP_STARTTLS_AUTO true or false (see ruby Mail library)
108
+
109
+ TALKTOME_BEARER_SECRET secret for the webapi, to let send emails to anyone
110
+ ```
111
+
112
+ ## Hacking Talktome
113
+
114
+ In pure Ruby:
115
+
116
+ ```
117
+ bundle install
118
+ bundle exec rake test
119
+ ```
120
+
121
+ Or using docker, please then use the `make` targets initially cooked for Jenkins:
122
+
123
+ ```
124
+ make image
125
+ make test
126
+ ```
127
+
128
+ ## Contributing
129
+
130
+ Please use github issues for questions and bugs, and pull requests for
131
+ submitting improvement proposals and new features.
132
+
133
+ ## Contributors
134
+
135
+ Enspirit (https://enspirit.be) and Klaro App (https://klaro.cards) are
136
+ both actively using, contributing and funding work on this library.
137
+ Please contact Bernard Lambeau for any question.
138
+
139
+ ## Licence
140
+
141
+ Webspicy is distributed under a MIT Licence, by Enspirit SRL.
data/lib/talktome.rb CHANGED
@@ -4,25 +4,39 @@ require 'mustache'
4
4
  require 'redcarpet'
5
5
  module Talktome
6
6
 
7
+ # Root folder of the project structure
8
+ ROOT_FOLDER = Path.backfind('.[Gemfile]') or raise("Missing Gemfile")
9
+
10
+ def env(which, default = nil)
11
+ if ENV.has_key?(which)
12
+ got = ENV[which].to_s.strip
13
+ return got unless got.empty?
14
+ end
15
+ default
16
+ end
17
+ module_function :env
18
+
19
+ def with_env(which, &bl)
20
+ env(which).tap{|x|
21
+ bl.call(x) unless x.nil?
22
+ }
23
+ end
24
+ module_function :with_env
25
+
26
+ def set_env(which, value, &bl)
27
+ old, ENV[which] = ENV[which], value
28
+ bl.call.tap{
29
+ ENV[which] = old
30
+ }
31
+ end
32
+ module_function :set_env
33
+
7
34
  def redcarpet
8
35
  @redcarpet ||= Redcarpet::Markdown.new(Redcarpet::Render::HTML, extensions = {})
9
36
  end
10
37
  module_function :redcarpet
11
38
 
12
- #
13
39
  # Infer all client and strategy options from environment variables.
14
- # The following ones are recognized:
15
- #
16
- # - TALKTOME_DEBUG: when set (to anything) enables the dumping of sent
17
- # messages to the debug folder
18
- # - TALKTOME_EMAIL_DELIVERY: "smtp", "file" or "test"
19
- # - TALKTOME_EMAIL_DEFAULT_FROM: default from address to use for email sending
20
- # - TALKTOME_SMTP_ADDRESS: host address for smtp sending
21
- # - TALKTOME_SMTP_PORT: port of smtp server to use
22
- # - TALKTOME_SMTP_DOMAIN: sending domain
23
- # - TALKTOME_SMTP_USER: user for smtp authentication
24
- # - TALKTOME_SMTP_PASSWORD: user for smtp authentication
25
- #
26
40
  def auto_options(folder)
27
41
  options = {}
28
42
  debug_folder = folder/"tmp"
@@ -40,10 +54,11 @@ module Talktome
40
54
 
41
55
  email_config.merge!({
42
56
  address: ENV['TALKTOME_SMTP_ADDRESS'],
43
- port: ENV['TALKTOME_SMTP_PORT'],
57
+ port: ENV['TALKTOME_SMTP_PORT'].to_i,
44
58
  domain: ENV['TALKTOME_SMTP_DOMAIN'],
45
59
  user_name: ENV['TALKTOME_SMTP_USER'],
46
- password: ENV['TALKTOME_SMTP_PASSWORD']
60
+ password: ENV['TALKTOME_SMTP_PASSWORD'],
61
+ enable_starttls_auto: (ENV['TALKTOME_SMTP_STARTTLS_AUTO'] != 'false')
47
62
  }) if email_delivery == :smtp
48
63
 
49
64
  email_config.merge!({
@@ -52,9 +67,21 @@ module Talktome
52
67
 
53
68
  options[:strategies][:email] = ::Talktome::Strategy::Email.new{|email|
54
69
  email.delivery_method(email_delivery, email_config)
55
- email.from(ENV['TALKTOME_EMAIL_DEFAULT_FROM']) if ENV['TALKTOME_EMAIL_DEFAULT_FROM']
70
+ with_env('TALKTOME_EMAIL_DEFAULT_FROM'){|default|
71
+ email.from(default)
72
+ }
73
+ with_env('TALKTOME_EMAIL_DEFAULT_TO'){|default|
74
+ email.to(default)
75
+ }
76
+ with_env('TALKTOME_EMAIL_DEFAULT_REPLYTO'){|default|
77
+ email.reply_to(default)
78
+ }
56
79
  }
57
80
 
81
+ if layouts_folder = ENV['TALKTOME_LAYOUTS_FOLDER']
82
+ options[:layouts] = Path(layouts_folder)
83
+ end
84
+
58
85
  options
59
86
  end
60
87
  module_function :auto_options
@@ -0,0 +1,78 @@
1
+ require 'sinatra'
2
+ require 'finitio'
3
+ require 'rack/robustness'
4
+ module Talktome
5
+ class App < Sinatra::Application
6
+
7
+ use Rack::Robustness do |g|
8
+ g.catch_all
9
+ g.status 500
10
+ g.content_type 'text/plain'
11
+ g.body{ "An error occured." }
12
+ end
13
+
14
+ set :raise_errors, true
15
+ set :show_exceptions, false
16
+
17
+ VALIDATION_SCHEMA = ::Finitio.system(<<~FIO)
18
+ @import finitio/data
19
+ Email = String(s | s =~ /^[^@]+@[^@]+$/ )
20
+ {
21
+ to :? Email
22
+ reply_to :? Email
23
+ ... : .Object
24
+ }
25
+ FIO
26
+
27
+ TALKTOME = Talktome::Client::Local.new(ROOT_FOLDER/'templates')
28
+
29
+ post %r{/([a-z-]+)/} do |action|
30
+ begin
31
+ as_array = info.map{|k,v| {'key' => k.capitalize, 'value' => v}}
32
+ subject = Talktome.env('TALKTOME_EMAIL_SUBJECT', 'Someone wants to reach you!')
33
+ footer = Talktome.env('TALKTOME_EMAIL_FOOTER', "Truly yours,\n
34
+ Sent by [Enspirit.be](https://enspirit.be/), contact us if you need help with any IT task.")
35
+ user = load_user_from_info!
36
+ TALKTOME.talktome(action, user, info.merge(allvars: as_array, subject: subject, footer: footer), [:email]){|email|
37
+ email.reply_to = info[:reply_to] if info.has_key?(:reply_to)
38
+ }
39
+ [ 200, { "Content-Type" => "text/plain"}, ["Ok"] ]
40
+ rescue JSON::ParserError
41
+ fail!("Invalid data")
42
+ rescue Finitio::Error => ex
43
+ fail!(ex.message)
44
+ rescue ::Talktome::InvalidEmailError => ex
45
+ fail!("Invalid email address")
46
+ end
47
+ end
48
+
49
+ private
50
+
51
+ def info
52
+ @info ||= VALIDATION_SCHEMA.dress(JSON.parse(request.body.read)).tap{|info|
53
+ not_a_robot!(info)
54
+ }
55
+ end
56
+
57
+ def load_user_from_info!
58
+ if to = info[:to]
59
+ secret = Talktome.env('TALKTOME_BEARER_SECRET')
60
+ fail!("Missing secret", 400) unless secret
61
+ fail!("Invalid secret", 401) unless "Bearer #{secret}" == env["HTTP_AUTHORIZATION"]
62
+ { email: info[:to] }
63
+ else
64
+ {}
65
+ end
66
+ end
67
+
68
+ def fail!(message, status = 400)
69
+ halt([ status, { "Content-Type" => "text/plain"}, [message] ])
70
+ end
71
+
72
+ def not_a_robot!(info)
73
+ # `reply_to_confirm` is a honeypot field, if it's filled it means it's a bot and an error is thrown
74
+ raise ::Talktome::InvalidEmailError if info[:reply_to_confirm] && info[:reply_to_confirm] =~ /^[^@]+@[^@]+$/
75
+ end
76
+
77
+ end # class App
78
+ end # module Talktome
@@ -33,7 +33,7 @@ module Talktome
33
33
  end
34
34
 
35
35
  def templater(strategy)
36
- return nil unless tpl_folder = options[:templates]
36
+ return nil unless tpl_folder = options[:layouts] || options[:templates]
37
37
  ->(message, src, ctype) {
38
38
  if (file = tpl_folder/"#{strategy}.#{ctype}").file?
39
39
  data = { metadata: message.metadata, yield: src }
@@ -1,4 +1,5 @@
1
1
  module Talktome
2
2
  class Error < StandardError; end
3
3
  class InvalidMessageError < Error; end
4
+ class InvalidEmailError < Error; end
4
5
  end
@@ -9,10 +9,23 @@ module Talktome
9
9
  end
10
10
 
11
11
  def send_message(message, user)
12
+ # Take a base email, with all info coming from the environment (if set)
12
13
  mail = base_email
13
- mail.to = user[:email]
14
- mail.reply_to = message.metadata["reply_to"] if message.metadata.has_key?("reply_to")
15
- mail.subject = message.metadata["subject"]
14
+
15
+ # Override environment defaults with template behavior, for flexibility
16
+ [
17
+ :to,
18
+ :reply_to,
19
+ :subject
20
+ ].each do |which|
21
+ if arg = message.metadata[which.to_s]
22
+ mail.send(:"#{which}=", arg)
23
+ end
24
+ end
25
+
26
+ # If the user is actually known from source code behavior, override the
27
+ # `mail.to` to send the email to that particular person.
28
+ mail.to = user[:email] if user.has_key?(:email)
16
29
 
17
30
  case message.extension
18
31
  when 'md', 'html', 'htm'
@@ -1,6 +1,6 @@
1
1
  module Talktome
2
2
  module Version
3
- MAJOR = 0
3
+ MAJOR = 1
4
4
  MINOR = 2
5
5
  TINY = 0
6
6
  end
@@ -0,0 +1,166 @@
1
+ require 'spec_helper'
2
+
3
+ module Talktome
4
+ describe App do
5
+ include Rack::Test::Methods
6
+
7
+ let(:app) {
8
+ Talktome::App.new
9
+ }
10
+
11
+ before(:each) do
12
+ ENV['TALKTOME_EMAIL_DEFAULT_TO'] = "to@talktome.com"
13
+ ENV['TALKTOME_EMAIL_DEFAULT_FROM'] = "from@talktome.com"
14
+ Mail::TestMailer.deliveries.clear
15
+ end
16
+
17
+ context 'POST /contact-us/, the basic contract' do
18
+
19
+ it 'works' do
20
+ post "/contact-us/", {
21
+ reply_to: 'hello@visitor.com',
22
+ message: 'Hello from visitor',
23
+ key: 'value',
24
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
25
+ expect(last_response).to be_ok
26
+ expect(Mail::TestMailer.deliveries.length).to eql(1)
27
+ expect(Mail::TestMailer.deliveries.first.to).to eql(["to@talktome.com"])
28
+ expect(Mail::TestMailer.deliveries.first.from).to eql(["from@talktome.com"])
29
+ expect(Mail::TestMailer.deliveries.first.subject).to eql("Someone wants to reach you!")
30
+ expect(Mail::TestMailer.deliveries.first.html_part.body).to include("<li>Key: value</li>")
31
+ expect(Mail::TestMailer.deliveries.first.html_part.body).to include("Truly yours")
32
+ end
33
+
34
+ it 'allows to use environment variable to tune the subject and the footer' do
35
+ Talktome.set_env('TALKTOME_EMAIL_SUBJECT', "Subject from environment") do
36
+ Talktome.set_env('TALKTOME_EMAIL_FOOTER', "Footer from environment") do
37
+ post "/contact-us/", {
38
+ reply_to: 'info@domain.com',
39
+ message: 'This is the message.'
40
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
41
+ expect(last_response).to be_ok
42
+ expect(Mail::TestMailer.deliveries.length).to eql(1)
43
+ expect(Mail::TestMailer.deliveries.first.subject).to eql("Subject from environment")
44
+ expect(Mail::TestMailer.deliveries.first.html_part.body).to include("Footer from environment")
45
+ end
46
+ end
47
+ end
48
+
49
+ it 'allows to use a token authentification to bypass default security measures, for e.g. passing the :to' do
50
+ Talktome.set_env('TALKTOME_BEARER_SECRET', "Some secret") do
51
+ header 'Authorization', 'Bearer Some secret'
52
+ post "/contact-us/", {
53
+ to: 'hello@visitor.com',
54
+ reply_to: 'hello@visitor.com',
55
+ message: 'Hello from visitor',
56
+ key: 'value',
57
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
58
+ expect(last_response).to be_ok
59
+ expect(Mail::TestMailer.deliveries.length).to eql(1)
60
+ expect(Mail::TestMailer.deliveries.first.to).to eql(["hello@visitor.com"])
61
+ expect(Mail::TestMailer.deliveries.first.from).to eql(["from@talktome.com"])
62
+ end
63
+ end
64
+
65
+ it 'detects invalid emails' do
66
+ post "/contact-us/", {
67
+ reply_to: 'helloatvisitor.com',
68
+ message: 'Hello from visitor'
69
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
70
+ expect(last_response.status).to eql(400)
71
+ expect(Mail::TestMailer.deliveries.length).to eql(0)
72
+ end
73
+
74
+ it "detects invalid bodies" do
75
+ post "/contact-us/", body: "foobar"
76
+ expect(last_response.status).to eql(400)
77
+ expect(Mail::TestMailer.deliveries.length).to eql(0)
78
+ end
79
+
80
+ it "detects stupid bots at least" do
81
+ post "/contact-us/", {
82
+ reply_to: 'hello@visitor.com',
83
+ message: 'Hello from visitor',
84
+ reply_to_confirm: 'hello@visitor.com'
85
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
86
+ expect(last_response.status).to eql(400)
87
+ expect(Mail::TestMailer.deliveries.length).to eql(0)
88
+ end
89
+
90
+ it 'forbids usage of :to unless a secret is provided' do
91
+ post "/contact-us/", {
92
+ to: 'hello@visitor.com',
93
+ reply_to: 'hello@visitor.com',
94
+ message: 'Hello from visitor',
95
+ key: 'value',
96
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
97
+ expect(last_response.status).to eql(400)
98
+ expect(Mail::TestMailer.deliveries.length).to eql(0)
99
+ end
100
+
101
+ it 'does not allow setting the :to without a valid AUTH token' do
102
+ Talktome.set_env('TALKTOME_BEARER_SECRET', "Invalid secret") do
103
+ post "/contact-us/", {
104
+ to: 'hello@visitor.com',
105
+ reply_to: 'hello@visitor.com',
106
+ message: 'Hello from visitor',
107
+ key: 'value',
108
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
109
+ expect(last_response.status).to eql(401)
110
+ expect(Mail::TestMailer.deliveries.length).to eql(0)
111
+ end
112
+ end
113
+
114
+ it 'requires a valid Email for :to' do
115
+ post "/contact-us/", {
116
+ to: nil,
117
+ reply_to: 'hello@visitor.com',
118
+ message: 'Hello from visitor',
119
+ key: 'value',
120
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
121
+ expect(last_response.status).to eql(400)
122
+
123
+ post "/contact-us/", {
124
+ to: "notavalidemail",
125
+ reply_to: 'hello@visitor.com',
126
+ message: 'Hello from visitor',
127
+ key: 'value',
128
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
129
+ expect(last_response.status).to eql(400)
130
+ end
131
+
132
+ end
133
+
134
+ context 'POST /contact-us/, regarding the Reply-To' do
135
+ class ::Talktome::Message::Template
136
+ def raise_on_context_miss?
137
+ false
138
+ end
139
+ end
140
+
141
+ around(:each) do |bl|
142
+ Talktome.set_env('TALKTOME_EMAIL_DEFAULT_REPLYTO', "replyto@talktome.com", &bl)
143
+ end
144
+
145
+ it 'takes the default value from environment if set' do
146
+ post "/contact-us/", {
147
+ message: 'Hello from visitor'
148
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
149
+ expect(last_response).to be_ok
150
+ expect(Mail::TestMailer.deliveries.length).to eql(1)
151
+ expect(Mail::TestMailer.deliveries.first.reply_to).to eql(["replyto@talktome.com"])
152
+ end
153
+
154
+ it "lets override it by passing a replyTo field" do
155
+ post "/contact-us/", {
156
+ reply_to: 'hello@visitor.com',
157
+ message: 'Hello from visitor'
158
+ }.to_json, { "CONTENT_TYPE" => "application/json" }
159
+ expect(last_response).to be_ok
160
+ expect(Mail::TestMailer.deliveries.length).to eql(1)
161
+ expect(Mail::TestMailer.deliveries.first.reply_to).to eql(["hello@visitor.com"])
162
+ end
163
+ end
164
+
165
+ end
166
+ end
@@ -29,7 +29,7 @@ module Talktome
29
29
  strategy.clear!
30
30
  }
31
31
 
32
- context "without templates" do
32
+ context "without layouts" do
33
33
  let(:options) {
34
34
  {}
35
35
  }
@@ -41,10 +41,10 @@ module Talktome
41
41
  end
42
42
  end
43
43
 
44
- context "with templates" do
44
+ context "with layouts under the :layouts option key" do
45
45
  let(:options) {
46
46
  {
47
- templates: Path.dir/"../fixtures/templates"
47
+ layouts: Path.dir/"../fixtures/layouts"
48
48
  }
49
49
  }
50
50
 
@@ -63,6 +63,19 @@ module Talktome
63
63
  end
64
64
  end
65
65
 
66
+ context "with layouts under the :templates option key (backward compatibility)" do
67
+ let(:options) {
68
+ {
69
+ templates: Path.dir/"../fixtures/layouts"
70
+ }
71
+ }
72
+
73
+ it 'sends email when requested' do
74
+ client.talktome("welcome", user, tpldata, [:email])
75
+ expect(strategy.last.message.to_html).to eql("<html><title>Hello Test user</title><body><h1>Hello Test user</h1>\n\n<p>Welcome to this email example!</p>\n\n<h3>Test user</h3>\n</body></html>\n")
76
+ end
77
+ end
78
+
66
79
  end
67
80
  end
68
81
  end
File without changes
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'talktome'
3
+ require 'talktome/app'
4
+ require 'rack/test'
3
5
 
4
6
  module SpecHelpers
5
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: talktome
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bernard Lambeau
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-20 00:00:00.000000000 Z
11
+ date: 2021-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -16,42 +16,56 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '10'
19
+ version: '13'
20
20
  type: :development
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '10'
26
+ version: '13'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rspec
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.6'
33
+ version: '3.10'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.6'
40
+ version: '3.10'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rack-test
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 0.6.3
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 0.6.3
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: path
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '1.3'
61
+ version: '2.0'
48
62
  type: :runtime
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '1.3'
68
+ version: '2.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: mail
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -100,6 +114,60 @@ dependencies:
100
114
  - - "~>"
101
115
  - !ruby/object:Gem::Version
102
116
  version: '3'
117
+ - !ruby/object:Gem::Dependency
118
+ name: sinatra
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '2.0'
124
+ - - "<"
125
+ - !ruby/object:Gem::Version
126
+ version: '3.0'
127
+ type: :runtime
128
+ prerelease: false
129
+ version_requirements: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '2.0'
134
+ - - "<"
135
+ - !ruby/object:Gem::Version
136
+ version: '3.0'
137
+ - !ruby/object:Gem::Dependency
138
+ name: finitio
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - ">="
142
+ - !ruby/object:Gem::Version
143
+ version: 0.10.0
144
+ - - "<"
145
+ - !ruby/object:Gem::Version
146
+ version: 0.11.0
147
+ type: :runtime
148
+ prerelease: false
149
+ version_requirements: !ruby/object:Gem::Requirement
150
+ requirements:
151
+ - - ">="
152
+ - !ruby/object:Gem::Version
153
+ version: 0.10.0
154
+ - - "<"
155
+ - !ruby/object:Gem::Version
156
+ version: 0.11.0
157
+ - !ruby/object:Gem::Dependency
158
+ name: rack-robustness
159
+ requirement: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - "~>"
162
+ - !ruby/object:Gem::Version
163
+ version: '1.1'
164
+ type: :runtime
165
+ prerelease: false
166
+ version_requirements: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - "~>"
169
+ - !ruby/object:Gem::Version
170
+ version: '1.1'
103
171
  description: Talktome helps you talk to users by email, messaging, sms, etc. It abstracts
104
172
  the messaging mechanisms and lets you manage message templates easily.
105
173
  email: blambeau@gmail.com
@@ -112,6 +180,7 @@ files:
112
180
  - README.md
113
181
  - Rakefile
114
182
  - lib/talktome.rb
183
+ - lib/talktome/app.rb
115
184
  - lib/talktome/client.rb
116
185
  - lib/talktome/client/local.rb
117
186
  - lib/talktome/error.rb
@@ -120,8 +189,9 @@ files:
120
189
  - lib/talktome/strategy/debug.rb
121
190
  - lib/talktome/strategy/email.rb
122
191
  - lib/talktome/version.rb
192
+ - spec/app/test_app.rb
123
193
  - spec/client/test_local.rb
124
- - spec/fixtures/templates/email.html
194
+ - spec/fixtures/layouts/email.html
125
195
  - spec/fixtures/welcome/email.md
126
196
  - spec/fixtures/welcome/footer.mustache
127
197
  - spec/message/test_initialize.rb
@@ -150,8 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
220
  - !ruby/object:Gem::Version
151
221
  version: '0'
152
222
  requirements: []
153
- rubyforge_project:
154
- rubygems_version: 2.6.11
223
+ rubygems_version: 3.2.15
155
224
  signing_key:
156
225
  specification_version: 4
157
226
  summary: Talktome helps you talk to users by email, messaging, sms, etc.