restpack_email_service 0.0.2
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 +17 -0
- data/.travis.yml +21 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +14 -0
- data/Rakefile +2 -0
- data/config/database.yml +8 -0
- data/db/migrate/20131010102904_create_email_configurations.rb +15 -0
- data/db/migrate/20131012115851_create_email_templates.rb +16 -0
- data/lib/restpack_email_service.rb +2 -0
- data/lib/restpack_email_service/commands/configuration/create.rb +22 -0
- data/lib/restpack_email_service/commands/configuration/list.rb +12 -0
- data/lib/restpack_email_service/commands/configuration/update.rb +46 -0
- data/lib/restpack_email_service/commands/template/create.rb +23 -0
- data/lib/restpack_email_service/commands/template/list.rb +13 -0
- data/lib/restpack_email_service/commands/template/update.rb +46 -0
- data/lib/restpack_email_service/configuration.rb +12 -0
- data/lib/restpack_email_service/jobs/email/send.rb +93 -0
- data/lib/restpack_email_service/jobs/email/send_raw.rb +53 -0
- data/lib/restpack_email_service/models/configuration.rb +10 -0
- data/lib/restpack_email_service/models/template.rb +36 -0
- data/lib/restpack_email_service/serializers/configuration.rb +12 -0
- data/lib/restpack_email_service/serializers/template.rb +12 -0
- data/lib/restpack_email_service/tasks/db.rake +39 -0
- data/lib/restpack_email_service/tasks/tasks.rb +7 -0
- data/lib/restpack_email_service/version.rb +7 -0
- data/restpack_email_service.gemspec +32 -0
- data/spec/commands/configuration/create_spec.rb +5 -0
- data/spec/commands/configuration/list_spec.rb +8 -0
- data/spec/commands/configuration/update_spec.rb +5 -0
- data/spec/commands/template/create_spec.rb +5 -0
- data/spec/commands/template/list_spec.rb +8 -0
- data/spec/commands/template/update_spec.rb +5 -0
- data/spec/factories/api_configuration.rb +13 -0
- data/spec/factories/api_template.rb +13 -0
- data/spec/factories/template.rb +9 -0
- data/spec/jobs/email/send_raw_spec.rb +5 -0
- data/spec/jobs/email/send_spec.rb +66 -0
- data/spec/models/configuration_spec.rb +9 -0
- data/spec/models/template_spec.rb +7 -0
- data/spec/spec_helper.rb +25 -0
- data/spec/templates/_footer.html.liquid +3 -0
- data/spec/templates/_footer.text.liquid +1 -0
- data/spec/templates/_header.html.liquid +3 -0
- data/spec/templates/_header.text.liquid +1 -0
- data/spec/templates/group.invitation.html.liquid +5 -0
- data/spec/templates/group.invitation.subject.liquid +1 -0
- data/spec/templates/group.invitation.text.liquid +5 -0
- data/templates/_footer.html.liquid +1 -0
- data/templates/_footer.text.liquid +2 -0
- data/templates/_header.html.liquid +1 -0
- data/templates/_header.text.liquid +2 -0
- data/templates/diagnostics.html.liquid +1 -0
- data/templates/diagnostics.subject.liquid +1 -0
- data/templates/diagnostics.text.liquid +1 -0
- data/templates/group.invitation.html.liquid +23 -0
- data/templates/group.invitation.subject.liquid +1 -0
- data/templates/group.invitation.text.liquid +5 -0
- metadata +263 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b502ee058c2cdfe1e1e8bd1be7a414d214e1c64e
|
4
|
+
data.tar.gz: f9c8baa8a6ac8af77dea4c39055d434cc0a38ee2
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e4df948c3add701a906843908ae08319a2369d1dbc14ff35d82677e5ffd94ced3f45aee4914f6c653f7139c8cd9c93dbbc67b830aebda107df63e517f741e248
|
7
|
+
data.tar.gz: 50b5e71cbcbf2b4846062987d950224e2f88c9957828c2f7fe0f23df1db84376d3a8c1da175af569dab30e9f2f9a0ef5afeec2d5d7ddd7a21b3ae667fcc7b74a
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.0.0
|
4
|
+
#http://reefpoints.dockyard.com/ruby/2013/03/29/running-postgresql-9-2-on-travis-ci.html
|
5
|
+
before_script:
|
6
|
+
- sudo /etc/init.d/postgresql stop
|
7
|
+
- sudo cp /etc/postgresql/9.1/main/pg_hba.conf ./
|
8
|
+
- sudo apt-get remove postgresql postgresql-9.1 -qq --purge
|
9
|
+
- source /etc/lsb-release
|
10
|
+
- echo "deb http://apt.postgresql.org/pub/repos/apt/ $DISTRIB_CODENAME-pgdg main" > pgdg.list
|
11
|
+
- sudo mv pgdg.list /etc/apt/sources.list.d/
|
12
|
+
- wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | sudo apt-key add -
|
13
|
+
- sudo apt-get update
|
14
|
+
- sudo apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confnew" install postgresql-9.2 postgresql-contrib-9.2 -qq
|
15
|
+
- sudo /etc/init.d/postgresql stop
|
16
|
+
- sudo cp ./pg_hba.conf /etc/postgresql/9.2/main
|
17
|
+
- sudo /etc/init.d/postgresql start
|
18
|
+
- psql -c 'create database restpack_email_service_test;' -U postgres
|
19
|
+
- psql -c 'create role travis login;' -U postgres
|
20
|
+
|
21
|
+
script: bundle exec rake test
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Gavin Joyce
|
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,14 @@
|
|
1
|
+
# restpack_email_service
|
2
|
+
|
3
|
+
[](https://travis-ci.org/RestPack/restpack_email_service) [](https://codeclimate.com/github/RestPack/restpack_email_service) [](https://gemnasium.com/RestPack/restpack_email_service) [](http://badge.fury.io/rb/restpack_email_service)
|
4
|
+
|
5
|
+
**Work In Progress**
|
6
|
+
|
7
|
+
This gem provides services for sending and receiving Emails.
|
8
|
+
|
9
|
+
## Development Setup
|
10
|
+
|
11
|
+
1. install postgres
|
12
|
+
2. create a `restpack_email_service_test` database
|
13
|
+
3. bundle
|
14
|
+
4. rake
|
data/Rakefile
ADDED
data/config/database.yml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateEmailConfigurations < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :restpack_email_configurations do |t|
|
4
|
+
t.integer :application_id, :null => false
|
5
|
+
t.integer :domain_id
|
6
|
+
t.string :smtp_server, :null => false, :limit => 1024
|
7
|
+
t.string :smtp_username, :null => false, :limit => 1024
|
8
|
+
t.string :smtp_password, :null => false, :limit => 1024
|
9
|
+
t.integer :smtp_port
|
10
|
+
t.string :default_from, :null => false, :limit => 512
|
11
|
+
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateEmailTemplates < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :restpack_email_templates do |t|
|
4
|
+
t.integer :application_id, :null => false
|
5
|
+
t.integer :domain_id
|
6
|
+
t.string :identifier, :null => false, :limit => 256
|
7
|
+
t.string :from, :limit => 512
|
8
|
+
t.string :subject_template, :null => false, :limit => 256
|
9
|
+
t.string :text_template, :limit => 65536
|
10
|
+
t.string :html_template, :limit => 65536
|
11
|
+
t.json :data, :null => false
|
12
|
+
|
13
|
+
t.timestamps
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Commands::Email::Configuration
|
2
|
+
class Create < RestPack::Service::Commands::Create
|
3
|
+
required do
|
4
|
+
array :configurations do
|
5
|
+
hash do
|
6
|
+
required do
|
7
|
+
integer :application_id
|
8
|
+
string :smtp_server
|
9
|
+
string :smtp_username
|
10
|
+
string :smtp_password
|
11
|
+
string :default_from
|
12
|
+
end
|
13
|
+
|
14
|
+
optional do
|
15
|
+
integer :domain_id
|
16
|
+
integer :smtp_port
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Commands::Email::Configuration
|
2
|
+
class Update < RestPack::Service::Command
|
3
|
+
required do
|
4
|
+
array :configurations do
|
5
|
+
hash do
|
6
|
+
required do
|
7
|
+
integer :id
|
8
|
+
integer :application_id
|
9
|
+
string :smtp_server
|
10
|
+
integer :smtp_port
|
11
|
+
string :smtp_username
|
12
|
+
string :smtp_password
|
13
|
+
string :default_from
|
14
|
+
end
|
15
|
+
|
16
|
+
optional do
|
17
|
+
integer :domain_id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def execute
|
24
|
+
#TODO: GJ: wrap in transaction
|
25
|
+
#TODO: GJ: extract to base class
|
26
|
+
result = {
|
27
|
+
configurations: []
|
28
|
+
}
|
29
|
+
|
30
|
+
inputs[:configurations].each do |item|
|
31
|
+
model = Models::Email::Configuration.find_by_id_and_application_id(
|
32
|
+
item[:id], item[:application_id]
|
33
|
+
)
|
34
|
+
|
35
|
+
if model
|
36
|
+
model.update_attributes(item)
|
37
|
+
result[:configurations] << Serializers::Email::Configuration.as_json(model)
|
38
|
+
else
|
39
|
+
status :not_found
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Commands::Email::Template
|
2
|
+
class Create < RestPack::Service::Commands::Create
|
3
|
+
required do
|
4
|
+
array :templates do
|
5
|
+
hash do
|
6
|
+
required do
|
7
|
+
integer :application_id
|
8
|
+
string :identifier
|
9
|
+
string :subject_template
|
10
|
+
end
|
11
|
+
|
12
|
+
optional do
|
13
|
+
integer :domain_id
|
14
|
+
string :from
|
15
|
+
string :text_template
|
16
|
+
string :html_template
|
17
|
+
model :data, class: Hash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Commands::Email::Template
|
2
|
+
class Update < RestPack::Service::Command
|
3
|
+
required do
|
4
|
+
array :email_templates do
|
5
|
+
hash do
|
6
|
+
required do
|
7
|
+
integer :id
|
8
|
+
integer :application_id
|
9
|
+
string :identifier
|
10
|
+
string :subject_template
|
11
|
+
end
|
12
|
+
|
13
|
+
optional do
|
14
|
+
integer :domain_id
|
15
|
+
string :from
|
16
|
+
string :text_template
|
17
|
+
string :html_template
|
18
|
+
model :data, class: Hash
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def execute
|
25
|
+
#TODO: GJ: wrap in transaction
|
26
|
+
result = {
|
27
|
+
email_templates: []
|
28
|
+
}
|
29
|
+
|
30
|
+
inputs[:email_templates].each do |email_template_inputs|
|
31
|
+
email_template = Models::Email:Template.find_by_id_and_application_id(
|
32
|
+
email_template_inputs[:id], email_template_inputs[:application_id]
|
33
|
+
)
|
34
|
+
|
35
|
+
if email_template
|
36
|
+
email_template.update_attributes(email_template_inputs)
|
37
|
+
result[:email_templates] << Serializers::Email::Template.as_json(email_template)
|
38
|
+
else
|
39
|
+
status :not_found
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return result
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
|
3
|
+
module Jobs::Email
|
4
|
+
class Send
|
5
|
+
include Sidekiq::Worker
|
6
|
+
|
7
|
+
def perform(params)
|
8
|
+
params.deep_symbolize_keys!
|
9
|
+
|
10
|
+
template = get_template(params)
|
11
|
+
|
12
|
+
if template
|
13
|
+
params[:subject] = template.render_subject(params[:data])
|
14
|
+
params[:text_body] = template.render_text(params[:data])
|
15
|
+
params[:html_body] = template.render_html(params[:data])
|
16
|
+
|
17
|
+
if template.from
|
18
|
+
params[:from] ||= template.from
|
19
|
+
end
|
20
|
+
|
21
|
+
send_raw.perform(params)
|
22
|
+
else
|
23
|
+
#TODO: GJ: logging exception
|
24
|
+
raise "Invalid template: #{params['template']}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def send_raw
|
31
|
+
Jobs::Email::SendRaw.new
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_template(params)
|
35
|
+
application_id = params[:application_id]
|
36
|
+
template = resolve_template(application_id, params[:template])
|
37
|
+
inject_header_and_footer(template, application_id)
|
38
|
+
|
39
|
+
template
|
40
|
+
end
|
41
|
+
|
42
|
+
def resolve_template(application_id, identifier)
|
43
|
+
template = Models::Email::Template.where(
|
44
|
+
application_id: application_id,
|
45
|
+
identifier: identifier
|
46
|
+
).take
|
47
|
+
|
48
|
+
template ||= Models::Email::Template.new
|
49
|
+
|
50
|
+
if template.subject_template.blank?
|
51
|
+
template.subject_template = load_default_template(identifier, 'subject')
|
52
|
+
end
|
53
|
+
|
54
|
+
if template.text_template.blank?
|
55
|
+
template.text_template = load_default_template(identifier, 'text')
|
56
|
+
end
|
57
|
+
|
58
|
+
if template.html_template.blank?
|
59
|
+
template.html_template = load_default_template(identifier, 'html')
|
60
|
+
end
|
61
|
+
|
62
|
+
template
|
63
|
+
end
|
64
|
+
|
65
|
+
def load_default_template(identifier, format='html')
|
66
|
+
filepath = File.expand_path("#{template_path}/#{identifier}.#{format}.liquid", __FILE__)
|
67
|
+
if File.exists? filepath
|
68
|
+
return File.read(filepath)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def template_path
|
73
|
+
'../../../../../templates'
|
74
|
+
end
|
75
|
+
|
76
|
+
def inject_header_and_footer(template, application_id)
|
77
|
+
if template
|
78
|
+
header = resolve_template(application_id, '_header')
|
79
|
+
footer = resolve_template(application_id, '_footer')
|
80
|
+
|
81
|
+
if template.html_template
|
82
|
+
template.html_template = template.html_template.gsub('{{header}}', header.html_template)
|
83
|
+
template.html_template = template.html_template.gsub('{{footer}}', footer.html_template)
|
84
|
+
end
|
85
|
+
|
86
|
+
if template.text_template
|
87
|
+
template.text_template = template.text_template.gsub('{{header}}', header.text_template)
|
88
|
+
template.text_template = template.text_template.gsub('{{footer}}', footer.text_template)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require 'mail'
|
3
|
+
|
4
|
+
module Jobs::Email
|
5
|
+
class SendRaw
|
6
|
+
include Sidekiq::Worker
|
7
|
+
|
8
|
+
def perform(params)
|
9
|
+
params.deep_symbolize_keys!
|
10
|
+
configuration = get_configuration(params)
|
11
|
+
|
12
|
+
Mail.defaults do
|
13
|
+
delivery_method :smtp, {
|
14
|
+
address: configuration[:smtp_server],
|
15
|
+
port: configuration[:smtp_port],
|
16
|
+
user_name: configuration[:smtp_username],
|
17
|
+
password: configuration[:smtp_password],
|
18
|
+
enable_starttls_auto: true
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
mail = Mail.new do
|
23
|
+
to params[:to]
|
24
|
+
from params[:from] || configuration[:default_from]
|
25
|
+
subject params[:subject]
|
26
|
+
|
27
|
+
text_part do
|
28
|
+
body params[:text_body]
|
29
|
+
end
|
30
|
+
|
31
|
+
if params[:html_body]
|
32
|
+
html_part do
|
33
|
+
content_type 'text/html; charset=UTF-8'
|
34
|
+
body params[:html_body]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
mail.deliver
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def get_configuration(params)
|
45
|
+
config = Serializers::Email::Configuration.resource(
|
46
|
+
application_id: params[:application_id]
|
47
|
+
)[:configurations]
|
48
|
+
|
49
|
+
raise "Email is not setup for this application" if config.empty?
|
50
|
+
return config.first
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Models::Email
|
2
|
+
class Configuration < ActiveRecord::Base
|
3
|
+
self.table_name = :restpack_email_configurations
|
4
|
+
|
5
|
+
attr_accessible :application_id, :domain_id, :smtp_server, :smtp_username,
|
6
|
+
:smtp_password, :smtp_port, :default_from
|
7
|
+
validates_presence_of :application_id, :smtp_server, :smtp_username,
|
8
|
+
:smtp_password, :default_from
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'liquid'
|
2
|
+
|
3
|
+
module Models::Email
|
4
|
+
class Template < ActiveRecord::Base
|
5
|
+
self.table_name = :restpack_email_templates
|
6
|
+
|
7
|
+
attr_accessible :application_id, :identifier, :from, :subject_template,
|
8
|
+
:text_template, :html_template, :data
|
9
|
+
validates_presence_of :application_id, :identifier, :subject_template,
|
10
|
+
:text_template, :html_template
|
11
|
+
|
12
|
+
before_save -> {
|
13
|
+
self.data ||= {}
|
14
|
+
}
|
15
|
+
|
16
|
+
def render_subject(data)
|
17
|
+
render(subject_template, data)
|
18
|
+
end
|
19
|
+
def render_text(data)
|
20
|
+
render(text_template, data)
|
21
|
+
end
|
22
|
+
def render_html(data)
|
23
|
+
render(html_template, data)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def render(template, data)
|
29
|
+
return nil unless template
|
30
|
+
|
31
|
+
data.deep_stringify_keys! if data
|
32
|
+
rendered = Liquid::Template.parse(template).render(data)
|
33
|
+
rendered.strip
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Serializers::Email
|
2
|
+
class Configuration
|
3
|
+
include RestPack::Serializer
|
4
|
+
|
5
|
+
self.model_class = Models::Email::Configuration
|
6
|
+
self.key = :configurations
|
7
|
+
|
8
|
+
attributes :id, :application_id, :domain_id, :smtp_server,
|
9
|
+
:smtp_username, :smtp_password, :smtp_port, :default_from
|
10
|
+
can_filter_by :application_id
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Serializers::Email
|
2
|
+
class Template
|
3
|
+
include RestPack::Serializer
|
4
|
+
|
5
|
+
self.model_class = Models::Email::Template
|
6
|
+
self.key = :templates
|
7
|
+
|
8
|
+
attributes :id, :application_id, :identifier, :subject_template,
|
9
|
+
:text_template, :html_template, :data
|
10
|
+
can_filter_by :application_id
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
namespace :restpack do
|
2
|
+
desc "Run any outstanding RestPack migrations"
|
3
|
+
task :migrate do
|
4
|
+
Rake::Task["restpack:email:migrate"].invoke
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "List RestPack configuration"
|
8
|
+
task :configuration do
|
9
|
+
Rake::Task["restpack:email:configuration"].invoke
|
10
|
+
end
|
11
|
+
|
12
|
+
namespace :email do
|
13
|
+
desc "Run any outstanding RestPack::Core migrations"
|
14
|
+
task :migrate => ["connection"] do
|
15
|
+
source_migrations_path = File.dirname(__FILE__) + "/../../../db/migrate"
|
16
|
+
target_migrations_path = "db/migrate"
|
17
|
+
|
18
|
+
ActiveRecord::Migration.verbose = true
|
19
|
+
ActiveRecord::Migrator.migrate(source_migrations_path)
|
20
|
+
|
21
|
+
if File.directory?(target_migrations_path)
|
22
|
+
FileUtils.cp_r(Dir["#{source_migrations_path}/*"], target_migrations_path)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
task :connection do
|
27
|
+
config = YAML.load(IO.read('config/database.yml'))
|
28
|
+
environment = ENV['RAILS_ENV'] || ENV['DB'] || 'development'
|
29
|
+
ActiveRecord::Base.establish_connection config[environment]
|
30
|
+
end
|
31
|
+
|
32
|
+
desc "List RestPack::Email::Service configuration"
|
33
|
+
task :configuration do
|
34
|
+
p "RestPack::Email::Service Configuration"
|
35
|
+
p "--------------------------------"
|
36
|
+
p "TODO"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'restpack_email_service/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "restpack_email_service"
|
8
|
+
spec.version = RestPack::Email::Service::VERSION
|
9
|
+
spec.authors = ["Gavin Joyce"]
|
10
|
+
spec.email = ["gavinjoyce@gmail.com"]
|
11
|
+
spec.description = %q{Email service}
|
12
|
+
spec.summary = %q{Send and receive emails}
|
13
|
+
spec.homepage = "https://github.com/RestPack"
|
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 "restpack_service"
|
22
|
+
spec.add_dependency "mail"
|
23
|
+
spec.add_dependency "liquid"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "database_cleaner", "~> 1.0.1"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
|
+
spec.add_development_dependency "bump"
|
30
|
+
spec.add_development_dependency "shoulda-matchers", "~> 1.4.2"
|
31
|
+
spec.add_development_dependency "factory_girl", "~> 4.0"
|
32
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :api_configuration, class: Hash do
|
3
|
+
sequence(:application_id)
|
4
|
+
|
5
|
+
sequence(:smtp_server) {|n| "smtp.domain#{n}.com" }
|
6
|
+
sequence(:smtp_username) {|n| "username_#{n}" }
|
7
|
+
sequence(:smtp_password) {|n| "password_#{n}" }
|
8
|
+
sequence(:default_from) {|n| "defaultfrom@domain#{n}.com" }
|
9
|
+
|
10
|
+
initialize_with { attributes }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :api_template, class: Hash do
|
3
|
+
sequence(:application_id)
|
4
|
+
|
5
|
+
sequence(:identifier) {|n| "template#{n}" }
|
6
|
+
sequence(:subject_template) {|n| "This is the subject #{n}" }
|
7
|
+
sequence(:html_template) {|n| "This is the <b>html</b> template #{n}" }
|
8
|
+
sequence(:text_template) {|n| "This is the text tempalte #{n}" }
|
9
|
+
|
10
|
+
initialize_with { attributes }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,9 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
factory :template, :class => Models::Email::Template do
|
3
|
+
sequence(:application_id)
|
4
|
+
sequence(:identifier) {|n| "template.#{n}" }
|
5
|
+
sequence(:subject_template) {|n| "This is the subject (#{n})" }
|
6
|
+
sequence(:text_template) {|n| "This is the text template (#{n})" }
|
7
|
+
sequence(:html_template) {|n| "This is the <b>html</b> template (#{n})" }
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Jobs::Email::Send do
|
4
|
+
let(:expected_raw_params) { {} }
|
5
|
+
before do
|
6
|
+
send_raw = double('send_raw')
|
7
|
+
send_raw.should_receive(:perform).with(expected_raw_params)
|
8
|
+
subject.stub(:send_raw).and_return(send_raw)
|
9
|
+
subject.stub(:template_path).and_return('../../../../../spec/templates')
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'custom templates' do
|
13
|
+
context 'simple template' do
|
14
|
+
let(:template) {
|
15
|
+
create(:template, subject_template: 'subject', text_template: 'text', html_template: 'html')
|
16
|
+
}
|
17
|
+
let(:expected_raw_params) { {
|
18
|
+
application_id: template[:application_id], template: template[:identifier],
|
19
|
+
subject: 'subject', text_body: 'text', html_body: 'html'
|
20
|
+
} }
|
21
|
+
|
22
|
+
it 'sends an email' do
|
23
|
+
subject.perform({ application_id: template.application_id, template: template.identifier })
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'with a default email address' do
|
28
|
+
let(:template) {
|
29
|
+
create(:template, subject_template: 'subject',
|
30
|
+
text_template: 'text', html_template: 'html', from: 'gavinjoyce@gmail.com')
|
31
|
+
}
|
32
|
+
let(:expected_raw_params) { {
|
33
|
+
application_id: template[:application_id], template: template[:identifier],
|
34
|
+
subject: 'subject', text_body: 'text', html_body: 'html', from: 'gavinjoyce@gmail.com'
|
35
|
+
} }
|
36
|
+
|
37
|
+
it 'sends an email' do
|
38
|
+
subject.perform({ application_id: template.application_id, template: template.identifier })
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with a default template' do
|
45
|
+
let(:data) { {
|
46
|
+
inviter_name: 'Gavin', group_name: 'MyHome.ie',
|
47
|
+
invitation: {
|
48
|
+
id: 999
|
49
|
+
}
|
50
|
+
} }
|
51
|
+
let(:expected_raw_params) { {
|
52
|
+
application_id: 142857, template: 'group.invitation',
|
53
|
+
subject: "Gavin has invited you to the MyHome.ie group",
|
54
|
+
text_body: "header text\n\n\ninvitation to ID: 999\n\nfooter text",
|
55
|
+
html_body: "<h1>header html</h1>\n\n<hr />\n\n\ninvitation to ID: 999\n\n<hr />\n\n<h2>footer html</h2>",
|
56
|
+
data: data
|
57
|
+
} }
|
58
|
+
|
59
|
+
it 'sends an email' do
|
60
|
+
subject.perform({
|
61
|
+
application_id: 142857, template: 'group.invitation',
|
62
|
+
data: data
|
63
|
+
})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Models::Email::Configuration do
|
4
|
+
it { should validate_presence_of(:application_id) }
|
5
|
+
it { should validate_presence_of(:smtp_server) }
|
6
|
+
it { should validate_presence_of(:smtp_username) }
|
7
|
+
it { should validate_presence_of(:smtp_password) }
|
8
|
+
it { should validate_presence_of(:default_from) }
|
9
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'restpack_service/support/spec_helper'
|
2
|
+
require 'restpack_email_service'
|
3
|
+
|
4
|
+
config = YAML.load_file('./config/database.yml')
|
5
|
+
ActiveRecord::Base.establish_connection(ENV['DATABASE_URL'] || config['test'])
|
6
|
+
|
7
|
+
migrations_path = File.dirname(__FILE__) + "/../db/migrate"
|
8
|
+
migrator = ActiveRecord::Migrator.new(:up, migrations_path)
|
9
|
+
migrator.migrate
|
10
|
+
|
11
|
+
FactoryGirl.find_definitions
|
12
|
+
|
13
|
+
DatabaseCleaner.strategy = :transaction
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.include FactoryGirl::Syntax::Methods
|
17
|
+
|
18
|
+
config.before(:each) do
|
19
|
+
DatabaseCleaner.start
|
20
|
+
end
|
21
|
+
|
22
|
+
config.after(:each) do
|
23
|
+
DatabaseCleaner.clean
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
footer text
|
@@ -0,0 +1 @@
|
|
1
|
+
header text
|
@@ -0,0 +1 @@
|
|
1
|
+
{{inviter_name}} has invited you to the {{group_name}} group
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>DEFAULT HTML FOOTER</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>DEFAULT HTML HEADER</h1>
|
@@ -0,0 +1 @@
|
|
1
|
+
this is the <b>diagnostocs</b> email
|
@@ -0,0 +1 @@
|
|
1
|
+
[RestPack] Diagnostics Email
|
@@ -0,0 +1 @@
|
|
1
|
+
this is the diagnostocs email
|
@@ -0,0 +1,23 @@
|
|
1
|
+
{{header}}
|
2
|
+
|
3
|
+
<h4>{{inviter}} wants you to join <span style="color: darkgreen">{{group.name}}</span> on ThingRoulette.</h4>
|
4
|
+
|
5
|
+
<div style="margin:20px">
|
6
|
+
<a style="display:inline-block;padding:7px 15px;background-color:#32b12c;color:#fff;font-size:16px;font-weight:bold;border-radius:2px;border:solid 1px #23891f;white-space:nowrap;text-decoration:none" href="{{accept_url}}" target="_blank">Yes Please</a>
|
7
|
+
|
|
8
|
+
<a style="display:inline-block;padding:7px 15px;background-color:#d44b38;color:#fff;font-size:16px;font-weight:bold;border-radius:2px;border:solid 1px #c43b28;white-space:nowrap;text-decoration:none" href="{{reject_url}}" target="_blank">No Thanks</a>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
{{footer}}
|
12
|
+
|
13
|
+
|
14
|
+
<hr />
|
15
|
+
{
|
16
|
+
"inviter": "Gavin Joyce",
|
17
|
+
"accept_url": "http://auth.restpack.org:8012/groups/rsvp?group_id=142857&key=ABCDEFG",
|
18
|
+
"reject_url": "http://auth.restpack.org:8012/groups/rsvp?group_id=142857&reject=1&key=ABCDEFG",
|
19
|
+
"group": {
|
20
|
+
"id": 142857,
|
21
|
+
"name": "Some Group"
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
this is the subject
|
metadata
ADDED
@@ -0,0 +1,263 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: restpack_email_service
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gavin Joyce
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-11-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: restpack_service
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '>='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '>='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: mail
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: liquid
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
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: bundler
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: database_cleaner
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 1.0.1
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 1.0.1
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - '>='
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
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: rspec
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: bump
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
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: shoulda-matchers
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ~>
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: 1.4.2
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ~>
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: 1.4.2
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: factory_girl
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ~>
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '4.0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ~>
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '4.0'
|
153
|
+
description: Email service
|
154
|
+
email:
|
155
|
+
- gavinjoyce@gmail.com
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- .gitignore
|
161
|
+
- .travis.yml
|
162
|
+
- Gemfile
|
163
|
+
- LICENSE.txt
|
164
|
+
- README.md
|
165
|
+
- Rakefile
|
166
|
+
- config/database.yml
|
167
|
+
- db/migrate/20131010102904_create_email_configurations.rb
|
168
|
+
- db/migrate/20131012115851_create_email_templates.rb
|
169
|
+
- lib/restpack_email_service.rb
|
170
|
+
- lib/restpack_email_service/commands/configuration/create.rb
|
171
|
+
- lib/restpack_email_service/commands/configuration/list.rb
|
172
|
+
- lib/restpack_email_service/commands/configuration/update.rb
|
173
|
+
- lib/restpack_email_service/commands/template/create.rb
|
174
|
+
- lib/restpack_email_service/commands/template/list.rb
|
175
|
+
- lib/restpack_email_service/commands/template/update.rb
|
176
|
+
- lib/restpack_email_service/configuration.rb
|
177
|
+
- lib/restpack_email_service/jobs/email/send.rb
|
178
|
+
- lib/restpack_email_service/jobs/email/send_raw.rb
|
179
|
+
- lib/restpack_email_service/models/configuration.rb
|
180
|
+
- lib/restpack_email_service/models/template.rb
|
181
|
+
- lib/restpack_email_service/serializers/configuration.rb
|
182
|
+
- lib/restpack_email_service/serializers/template.rb
|
183
|
+
- lib/restpack_email_service/tasks/db.rake
|
184
|
+
- lib/restpack_email_service/tasks/tasks.rb
|
185
|
+
- lib/restpack_email_service/version.rb
|
186
|
+
- restpack_email_service.gemspec
|
187
|
+
- spec/commands/configuration/create_spec.rb
|
188
|
+
- spec/commands/configuration/list_spec.rb
|
189
|
+
- spec/commands/configuration/update_spec.rb
|
190
|
+
- spec/commands/template/create_spec.rb
|
191
|
+
- spec/commands/template/list_spec.rb
|
192
|
+
- spec/commands/template/update_spec.rb
|
193
|
+
- spec/factories/api_configuration.rb
|
194
|
+
- spec/factories/api_template.rb
|
195
|
+
- spec/factories/template.rb
|
196
|
+
- spec/jobs/email/send_raw_spec.rb
|
197
|
+
- spec/jobs/email/send_spec.rb
|
198
|
+
- spec/models/configuration_spec.rb
|
199
|
+
- spec/models/template_spec.rb
|
200
|
+
- spec/spec_helper.rb
|
201
|
+
- spec/templates/_footer.html.liquid
|
202
|
+
- spec/templates/_footer.text.liquid
|
203
|
+
- spec/templates/_header.html.liquid
|
204
|
+
- spec/templates/_header.text.liquid
|
205
|
+
- spec/templates/group.invitation.html.liquid
|
206
|
+
- spec/templates/group.invitation.subject.liquid
|
207
|
+
- spec/templates/group.invitation.text.liquid
|
208
|
+
- templates/_footer.html.liquid
|
209
|
+
- templates/_footer.text.liquid
|
210
|
+
- templates/_header.html.liquid
|
211
|
+
- templates/_header.text.liquid
|
212
|
+
- templates/diagnostics.html.liquid
|
213
|
+
- templates/diagnostics.subject.liquid
|
214
|
+
- templates/diagnostics.text.liquid
|
215
|
+
- templates/group.invitation.html.liquid
|
216
|
+
- templates/group.invitation.subject.liquid
|
217
|
+
- templates/group.invitation.text.liquid
|
218
|
+
homepage: https://github.com/RestPack
|
219
|
+
licenses:
|
220
|
+
- MIT
|
221
|
+
metadata: {}
|
222
|
+
post_install_message:
|
223
|
+
rdoc_options: []
|
224
|
+
require_paths:
|
225
|
+
- lib
|
226
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
227
|
+
requirements:
|
228
|
+
- - '>='
|
229
|
+
- !ruby/object:Gem::Version
|
230
|
+
version: '0'
|
231
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
232
|
+
requirements:
|
233
|
+
- - '>='
|
234
|
+
- !ruby/object:Gem::Version
|
235
|
+
version: '0'
|
236
|
+
requirements: []
|
237
|
+
rubyforge_project:
|
238
|
+
rubygems_version: 2.0.7
|
239
|
+
signing_key:
|
240
|
+
specification_version: 4
|
241
|
+
summary: Send and receive emails
|
242
|
+
test_files:
|
243
|
+
- spec/commands/configuration/create_spec.rb
|
244
|
+
- spec/commands/configuration/list_spec.rb
|
245
|
+
- spec/commands/configuration/update_spec.rb
|
246
|
+
- spec/commands/template/create_spec.rb
|
247
|
+
- spec/commands/template/list_spec.rb
|
248
|
+
- spec/commands/template/update_spec.rb
|
249
|
+
- spec/factories/api_configuration.rb
|
250
|
+
- spec/factories/api_template.rb
|
251
|
+
- spec/factories/template.rb
|
252
|
+
- spec/jobs/email/send_raw_spec.rb
|
253
|
+
- spec/jobs/email/send_spec.rb
|
254
|
+
- spec/models/configuration_spec.rb
|
255
|
+
- spec/models/template_spec.rb
|
256
|
+
- spec/spec_helper.rb
|
257
|
+
- spec/templates/_footer.html.liquid
|
258
|
+
- spec/templates/_footer.text.liquid
|
259
|
+
- spec/templates/_header.html.liquid
|
260
|
+
- spec/templates/_header.text.liquid
|
261
|
+
- spec/templates/group.invitation.html.liquid
|
262
|
+
- spec/templates/group.invitation.subject.liquid
|
263
|
+
- spec/templates/group.invitation.text.liquid
|