resque-maktoub 0.2.5
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.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +55 -0
- data/Rakefile +43 -0
- data/app/assets/javascripts/maktoub/application.js +9 -0
- data/app/assets/javascripts/maktoub/archives.js +2 -0
- data/app/assets/stylesheets/maktoub/application.css +7 -0
- data/app/assets/stylesheets/maktoub/archives.css +4 -0
- data/app/controllers/maktoub/application_controller.rb +4 -0
- data/app/controllers/maktoub/archives_controller.rb +14 -0
- data/app/controllers/maktoub/subscribers_controller.rb +20 -0
- data/app/helpers/maktoub/application_helper.rb +4 -0
- data/app/helpers/maktoub/archives_helper.rb +4 -0
- data/app/mailers/maktoub/newsletter_mailer.rb +34 -0
- data/app/views/layouts/maktoub/_styles.erb +327 -0
- data/app/views/layouts/maktoub/application.html.erb +23 -0
- data/app/views/layouts/maktoub/newsletter_mailer.erb +165 -0
- data/app/views/maktoub/newsletters/readme.erb +3 -0
- data/app/views/maktoub/subscribers/edit.html.erb +16 -0
- data/app/views/maktoub/subscribers/update.html.erb +1 -0
- data/config/routes.rb +10 -0
- data/lib/generators/maktoub/USAGE +3 -0
- data/lib/generators/maktoub/config_generator.rb +11 -0
- data/lib/generators/maktoub/templates/maktoub.rb +22 -0
- data/lib/maktoub.rb +46 -0
- data/lib/maktoub/engine.rb +6 -0
- data/lib/maktoub/version.rb +4 -0
- data/lib/tasks/maktoub_tasks.rake +29 -0
- metadata +169 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2011 YOURNAME
|
2
|
+
|
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:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
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.rdoc
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
= Maktoub
|
2
|
+
|
3
|
+
Maktoub is a Ruby on Rails engine for email newsletters.
|
4
|
+
* Write your newsletter as you would write any view (erb partial)
|
5
|
+
* Maktoub sends your email in multipart as both html and text
|
6
|
+
|
7
|
+
|
8
|
+
== Installation
|
9
|
+
|
10
|
+
# Add this line to your Gemfile
|
11
|
+
gem 'resque-maktoub'
|
12
|
+
|
13
|
+
Then 'bundle install'
|
14
|
+
|
15
|
+
== Usage
|
16
|
+
|
17
|
+
=== Configuration
|
18
|
+
|
19
|
+
You can run 'rails generate maktoub:config' to generate the configuration file. This task creates a matkoub.rb initializer file (in config/initializer)
|
20
|
+
Follow instructions inside the file to configure it the way you want.
|
21
|
+
|
22
|
+
=== Authoring
|
23
|
+
|
24
|
+
Create a newsletter as a normal view partial in app/views/maktoub/newsletters/.
|
25
|
+
The subject of the newsletter will be automatically deduced from the partial's name.
|
26
|
+
|
27
|
+
=== Editing Styles
|
28
|
+
|
29
|
+
Create a view partial in app/views/layouts/maktoub/_styles.erb. Note that this completely overrides the styles that come with maktoub.
|
30
|
+
You can copy the built-in styles and override them.
|
31
|
+
|
32
|
+
=== Sending messages
|
33
|
+
Maktoub comes with two rake tasks to allow you to:
|
34
|
+
* send a test message to the "from" address of your newsletter.
|
35
|
+
|
36
|
+
rake maktoub:test['name_of_my_newsletter_partial']
|
37
|
+
|
38
|
+
* publish the newsletter to all your subscribers. If you have delayed_job installed then it will use it to deliver each email as a background job
|
39
|
+
|
40
|
+
rake maktoub:mail['name_of_my_newsletter_parial']
|
41
|
+
|
42
|
+
|
43
|
+
Alternatively you have access to a Maktoub::NewsletterMailer ActionMailer object with a publish method
|
44
|
+
Maktoub::NewsletterMail.publish('my_newsletter_partial', :name => 'User name', :email => 'user@example.com')
|
45
|
+
|
46
|
+
=== View in browser
|
47
|
+
To be able to view your newsletter in a browser add it to routes.rb.
|
48
|
+
# mount the engine at a path of your choice.
|
49
|
+
# you would access the newsletter at: http://example.com/newsletter/my_awesome_newletter
|
50
|
+
mount Maktoub::Engine => "/"
|
51
|
+
|
52
|
+
== Contributing
|
53
|
+
Send a pull request including documentation changes and tests.
|
54
|
+
|
55
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Maktoub'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
|
24
|
+
load 'rails/tasks/engine.rake'
|
25
|
+
|
26
|
+
|
27
|
+
Bundler::GemHelper.install_tasks
|
28
|
+
|
29
|
+
require 'rspec/core/rake_task'
|
30
|
+
|
31
|
+
RSpec::Core::RakeTask.new(:spec)
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
|
35
|
+
#Rake::TestTask.new(:test) do |t|
|
36
|
+
# t.libs << 'lib'
|
37
|
+
# t.libs << 'spec'
|
38
|
+
# t.pattern = 'spec/**/*_spec.rb'
|
39
|
+
# t.verbose = false
|
40
|
+
#end
|
41
|
+
|
42
|
+
|
43
|
+
#task :default => :test
|
@@ -0,0 +1,9 @@
|
|
1
|
+
// This is a manifest file that'll be compiled into including all the files listed below.
|
2
|
+
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
|
3
|
+
// be included in the compiled file accessible from http://example.com/assets/application.js
|
4
|
+
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
5
|
+
// the compiled file.
|
6
|
+
//
|
7
|
+
//= require jquery
|
8
|
+
//= require jquery_ujs
|
9
|
+
//= require_tree .
|
@@ -0,0 +1,7 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll automatically include all the stylesheets available in this directory
|
3
|
+
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
|
4
|
+
* the top of the compiled file, but it's generally better to create a new file per style scope.
|
5
|
+
*= require_self
|
6
|
+
*= require_tree .
|
7
|
+
*/
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Maktoub
|
2
|
+
class ArchivesController < ApplicationController
|
3
|
+
layout 'maktoub/newsletter_mailer'
|
4
|
+
def show
|
5
|
+
@archive = true
|
6
|
+
template = params[:newsletter] || 'readme'
|
7
|
+
@subject = template.titleize
|
8
|
+
|
9
|
+
render "maktoub/newsletters/#{template}"
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Maktoub
|
2
|
+
class SubscribersController < ApplicationController
|
3
|
+
layout 'maktoub/application'
|
4
|
+
|
5
|
+
def edit
|
6
|
+
|
7
|
+
end
|
8
|
+
|
9
|
+
def update
|
10
|
+
if params[:email].blank?
|
11
|
+
@message = "email is required"
|
12
|
+
render :edit, :status => 400
|
13
|
+
else
|
14
|
+
Maktoub.unsubscribe params[:email]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'premailer'
|
2
|
+
|
3
|
+
module Maktoub
|
4
|
+
class NewsletterMailer < ActionMailer::Base
|
5
|
+
include Resque::Mailer
|
6
|
+
|
7
|
+
default from: Maktoub.from,
|
8
|
+
parts_order: [ "text/html", "text/plain" ]
|
9
|
+
|
10
|
+
default_url_options[:host] = Maktoub.home_domain
|
11
|
+
|
12
|
+
def publish(newsletter_name, params)
|
13
|
+
@name = params[:name]
|
14
|
+
@subject = newsletter_name.humanize.titleize
|
15
|
+
@email = params[:email]
|
16
|
+
@newsletter_name = newsletter_name
|
17
|
+
mail_fields = {
|
18
|
+
subject: @subject,
|
19
|
+
to: params[:email]
|
20
|
+
}
|
21
|
+
|
22
|
+
premailer = Premailer.new(render("maktoub/newsletters/#{newsletter_name}").to_s,
|
23
|
+
with_html_string: true,
|
24
|
+
link_query_string: CGI::escape("utm_source=newsletter&utm_medium=email&utm_campaign=#{@subject}")
|
25
|
+
)
|
26
|
+
|
27
|
+
mail(mail_fields) do |format|
|
28
|
+
format.text { premailer.to_plain_text.html_safe }
|
29
|
+
format.html { premailer.to_inline_css.html_safe }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
@@ -0,0 +1,327 @@
|
|
1
|
+
/* Client-specific Styles */
|
2
|
+
#outlook a{padding:0;} /* Force Outlook to provide a "view in browser" button. */
|
3
|
+
body{width:100% !important;} .ReadMsgBody{width:100%;} .ExternalClass{width:100%;} /* Force Hotmail to display emails at full width */
|
4
|
+
body{-webkit-text-size-adjust:none;} /* Prevent Webkit platforms from changing default text sizes. */
|
5
|
+
|
6
|
+
/* Reset Styles */
|
7
|
+
body{margin:0; padding:0;}
|
8
|
+
img{border:0; height:auto; line-height:100%; outline:none; text-decoration:none;}
|
9
|
+
table td{border-collapse:collapse;}
|
10
|
+
#backgroundTable{height:100% !important; margin:0; padding:0; width:100% !important;}
|
11
|
+
|
12
|
+
/* Template Styles */
|
13
|
+
|
14
|
+
/* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: COMMON PAGE ELEMENTS /\/\/\/\/\/\/\/\/\/\ */
|
15
|
+
|
16
|
+
/**
|
17
|
+
* @tab Page
|
18
|
+
* @section background color
|
19
|
+
* @tip Set the background color for your email. You may want to choose one that matches your company's branding.
|
20
|
+
* @theme page
|
21
|
+
*/
|
22
|
+
body, #backgroundTable{
|
23
|
+
background-color:#FCFCFC;
|
24
|
+
}
|
25
|
+
|
26
|
+
hr {
|
27
|
+
margin-top: 0;
|
28
|
+
color: #CCCCCC;
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
* @tab Page
|
33
|
+
* @section email border
|
34
|
+
* @tip Set the border for your email.
|
35
|
+
*/
|
36
|
+
#templateContainer{
|
37
|
+
|
38
|
+
}
|
39
|
+
|
40
|
+
/**
|
41
|
+
* @tab Page
|
42
|
+
* @section heading 1
|
43
|
+
* @tip Set the styling for all first-level headings in your emails. These should be the largest of your headings.
|
44
|
+
* @style heading 1
|
45
|
+
*/
|
46
|
+
h1, .h1{
|
47
|
+
color: #0099FF;
|
48
|
+
display:block;
|
49
|
+
font-family:Arial;
|
50
|
+
font-size:34px;
|
51
|
+
font-weight:bold;
|
52
|
+
line-height:100%;
|
53
|
+
margin-top:0;
|
54
|
+
margin-right:0;
|
55
|
+
margin-bottom:10px;
|
56
|
+
margin-left:0;
|
57
|
+
text-align:left;
|
58
|
+
}
|
59
|
+
|
60
|
+
/**
|
61
|
+
* @tab Page
|
62
|
+
* @section heading 2
|
63
|
+
* @tip Set the styling for all second-level headings in your emails.
|
64
|
+
* @style heading 2
|
65
|
+
*/
|
66
|
+
h2, .h2{
|
67
|
+
color: #0099FF;
|
68
|
+
display:block;
|
69
|
+
font-family:Arial;
|
70
|
+
font-size:30px;
|
71
|
+
font-weight:bold;
|
72
|
+
line-height:100%;
|
73
|
+
margin-top:0;
|
74
|
+
margin-right:0;
|
75
|
+
margin-bottom:10px;
|
76
|
+
margin-left:0;
|
77
|
+
text-align:left;
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* @tab Page
|
82
|
+
* @section heading 3
|
83
|
+
* @tip Set the styling for all third-level headings in your emails.
|
84
|
+
* @style heading 3
|
85
|
+
*/
|
86
|
+
h3, .h3{
|
87
|
+
color: #0099FF;
|
88
|
+
display:block;
|
89
|
+
font-family:Arial;
|
90
|
+
font-size:26px;
|
91
|
+
font-weight:bold;
|
92
|
+
line-height:100%;
|
93
|
+
margin-top:0;
|
94
|
+
margin-right:0;
|
95
|
+
margin-bottom:10px;
|
96
|
+
margin-left:0;
|
97
|
+
text-align:left;
|
98
|
+
}
|
99
|
+
|
100
|
+
/**
|
101
|
+
* @tab Page
|
102
|
+
* @section heading 4
|
103
|
+
* @tip Set the styling for all fourth-level headings in your emails. These should be the smallest of your headings.
|
104
|
+
* @style heading 4
|
105
|
+
*/
|
106
|
+
h4, .h4{
|
107
|
+
color: #0099FF;
|
108
|
+
display:block;
|
109
|
+
font-family:Arial;
|
110
|
+
font-size:22px;
|
111
|
+
font-weight:bold;
|
112
|
+
line-height:100%;
|
113
|
+
margin-top:0;
|
114
|
+
margin-right:0;
|
115
|
+
margin-bottom:10px;
|
116
|
+
margin-left:0;
|
117
|
+
text-align:left;
|
118
|
+
}
|
119
|
+
|
120
|
+
/* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: PREHEADER /\/\/\/\/\/\/\/\/\/\ */
|
121
|
+
|
122
|
+
/**
|
123
|
+
* @tab Header
|
124
|
+
* @section preheader style
|
125
|
+
* @tip Set the background color for your email's preheader area.
|
126
|
+
* @theme page
|
127
|
+
*/
|
128
|
+
#templatePreheader{
|
129
|
+
background-color:#FCFCFC;
|
130
|
+
}
|
131
|
+
|
132
|
+
/**
|
133
|
+
* @tab Header
|
134
|
+
* @section preheader text
|
135
|
+
* @tip Set the styling for your email's preheader text. Choose a size and color that is easy to read.
|
136
|
+
*/
|
137
|
+
.preheaderContent div{
|
138
|
+
color:#505050;
|
139
|
+
font-family:Arial;
|
140
|
+
font-size:10px;
|
141
|
+
line-height:100%;
|
142
|
+
text-align:left;
|
143
|
+
}
|
144
|
+
|
145
|
+
/**
|
146
|
+
* @tab Header
|
147
|
+
* @section preheader link
|
148
|
+
* @tip Set the styling for your email's preheader links. Choose a color that helps them stand out from your text.
|
149
|
+
*/
|
150
|
+
.preheaderContent div a:link, .preheaderContent div a:visited, /* Yahoo! Mail Override */ .preheaderContent div a .yshortcuts /* Yahoo! Mail Override */{
|
151
|
+
color:#336699;
|
152
|
+
font-weight:normal;
|
153
|
+
text-decoration:underline;
|
154
|
+
}
|
155
|
+
|
156
|
+
/* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: HEADER /\/\/\/\/\/\/\/\/\/\ */
|
157
|
+
|
158
|
+
/**
|
159
|
+
* @tab Header
|
160
|
+
* @section header style
|
161
|
+
* @tip Set the background color and border for your email's header area.
|
162
|
+
* @theme header
|
163
|
+
*/
|
164
|
+
#templateHeader{
|
165
|
+
background-color:#FCFCFC;
|
166
|
+
border-bottom:0;
|
167
|
+
}
|
168
|
+
|
169
|
+
/**
|
170
|
+
* @tab Header
|
171
|
+
* @section header text
|
172
|
+
* @tip Set the styling for your email's header text. Choose a size and color that is easy to read.
|
173
|
+
*/
|
174
|
+
.headerContent{
|
175
|
+
color:#202020;
|
176
|
+
font-family:Arial;
|
177
|
+
font-size:34px;
|
178
|
+
font-weight:bold;
|
179
|
+
line-height:100%;
|
180
|
+
padding:0;
|
181
|
+
text-align:left;
|
182
|
+
vertical-align:middle;
|
183
|
+
}
|
184
|
+
|
185
|
+
/**
|
186
|
+
* @tab Header
|
187
|
+
* @section header link
|
188
|
+
* @tip Set the styling for your email's header links. Choose a color that helps them stand out from your text.
|
189
|
+
*/
|
190
|
+
.headerContent a:link, .headerContent a:visited, /* Yahoo! Mail Override */ .headerContent a .yshortcuts /* Yahoo! Mail Override */{
|
191
|
+
color:#336699;
|
192
|
+
font-weight:normal;
|
193
|
+
text-decoration:underline;
|
194
|
+
}
|
195
|
+
|
196
|
+
#headerImage{
|
197
|
+
height:auto;
|
198
|
+
max-width:600px !important;
|
199
|
+
}
|
200
|
+
|
201
|
+
/* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: MAIN BODY /\/\/\/\/\/\/\/\/\/\ */
|
202
|
+
|
203
|
+
/**
|
204
|
+
* @tab Body
|
205
|
+
* @section body style
|
206
|
+
* @tip Set the background color for your email's body area.
|
207
|
+
*/
|
208
|
+
#templateContainer, .bodyContent{
|
209
|
+
background-color:#FCFCFC;
|
210
|
+
}
|
211
|
+
|
212
|
+
/**
|
213
|
+
* @tab Body
|
214
|
+
* @section body text
|
215
|
+
* @tip Set the styling for your email's main content text. Choose a size and color that is easy to read.
|
216
|
+
* @theme main
|
217
|
+
*/
|
218
|
+
.bodyContent div{
|
219
|
+
color:#505050;
|
220
|
+
font-family:Arial;
|
221
|
+
font-size:14px;
|
222
|
+
line-height:150%;
|
223
|
+
text-align:left;
|
224
|
+
}
|
225
|
+
|
226
|
+
/**
|
227
|
+
* @tab Body
|
228
|
+
* @section body link
|
229
|
+
* @tip Set the styling for your email's main content links. Choose a color that helps them stand out from your text.
|
230
|
+
*/
|
231
|
+
.bodyContent div a:link, .bodyContent div a:visited, /* Yahoo! Mail Override */ .bodyContent div a .yshortcuts /* Yahoo! Mail Override */{
|
232
|
+
color:#336699;
|
233
|
+
font-weight:normal;
|
234
|
+
text-decoration:underline;
|
235
|
+
}
|
236
|
+
|
237
|
+
.bodyContent img{
|
238
|
+
display:inline;
|
239
|
+
height:auto;
|
240
|
+
}
|
241
|
+
|
242
|
+
/* /\/\/\/\/\/\/\/\/\/\ STANDARD STYLING: FOOTER /\/\/\/\/\/\/\/\/\/\ */
|
243
|
+
|
244
|
+
/**
|
245
|
+
* @tab Footer
|
246
|
+
* @section footer style
|
247
|
+
* @tip Set the background color and top border for your email's footer area.
|
248
|
+
* @theme footer
|
249
|
+
*/
|
250
|
+
#templateFooter{
|
251
|
+
background-color:#FCFCFC;
|
252
|
+
border-top:0;
|
253
|
+
}
|
254
|
+
|
255
|
+
/**
|
256
|
+
* @tab Footer
|
257
|
+
* @section footer text
|
258
|
+
* @tip Set the styling for your email's footer text. Choose a size and color that is easy to read.
|
259
|
+
* @theme footer
|
260
|
+
*/
|
261
|
+
.footerContent div{
|
262
|
+
color:#707070;
|
263
|
+
font-family:Arial;
|
264
|
+
font-size:12px;
|
265
|
+
line-height:125%;
|
266
|
+
text-align:left;
|
267
|
+
}
|
268
|
+
|
269
|
+
/**
|
270
|
+
* @tab Footer
|
271
|
+
* @section footer link
|
272
|
+
* @tip Set the styling for your email's footer links. Choose a color that helps them stand out from your text.
|
273
|
+
*/
|
274
|
+
.footerContent div a:link, .footerContent div a:visited, /* Yahoo! Mail Override */ .footerContent div a .yshortcuts /* Yahoo! Mail Override */{
|
275
|
+
color:#336699;
|
276
|
+
font-weight:normal;
|
277
|
+
text-decoration:underline;
|
278
|
+
}
|
279
|
+
|
280
|
+
.footerContent img{
|
281
|
+
display:inline;
|
282
|
+
}
|
283
|
+
|
284
|
+
/**
|
285
|
+
* @tab Footer
|
286
|
+
* @section social bar style
|
287
|
+
* @tip Set the background color and border for your email's footer social bar.
|
288
|
+
* @theme footer
|
289
|
+
*/
|
290
|
+
#social{
|
291
|
+
background-color:#FCFCFC;
|
292
|
+
border:0;
|
293
|
+
}
|
294
|
+
|
295
|
+
/**
|
296
|
+
* @tab Footer
|
297
|
+
* @section social bar style
|
298
|
+
* @tip Set the background color and border for your email's footer social bar.
|
299
|
+
*/
|
300
|
+
#social div{
|
301
|
+
text-align:center;
|
302
|
+
}
|
303
|
+
|
304
|
+
/**
|
305
|
+
* @tab Footer
|
306
|
+
* @section utility bar style
|
307
|
+
* @tip Set the background color and border for your email's footer utility bar.
|
308
|
+
* @theme footer
|
309
|
+
*/
|
310
|
+
#utility{
|
311
|
+
background-color:#FCFCFC;
|
312
|
+
border:0;
|
313
|
+
}
|
314
|
+
|
315
|
+
/**
|
316
|
+
* @tab Footer
|
317
|
+
* @section utility bar style
|
318
|
+
* @tip Set the background color and border for your email's footer utility bar.
|
319
|
+
*/
|
320
|
+
#utility div{
|
321
|
+
text-align:center;
|
322
|
+
}
|
323
|
+
|
324
|
+
#monkeyRewards img{
|
325
|
+
max-width:190px;
|
326
|
+
}
|
327
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<title>Maktoub</title>
|
5
|
+
<%= stylesheet_link_tag "maktoub/application" %>
|
6
|
+
<%= javascript_include_tag "maktoub/application" %>
|
7
|
+
<%= csrf_meta_tags %>
|
8
|
+
<style type="text/css">
|
9
|
+
<%= render 'layouts/maktoub/styles' %>
|
10
|
+
div.container {
|
11
|
+
width: 600px;
|
12
|
+
margin: auto;
|
13
|
+
margin-top: 50px;
|
14
|
+
}
|
15
|
+
</style>
|
16
|
+
</head>
|
17
|
+
<body>
|
18
|
+
<div class="container">
|
19
|
+
<%= yield %>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
</body>
|
23
|
+
</html>
|
@@ -0,0 +1,165 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
5
|
+
|
6
|
+
<!-- Facebook sharing information tags -->
|
7
|
+
<meta property="og:title" content="<%= @subject %>" />
|
8
|
+
<meta name="viewport" content="width=680px, initial-scale=0.5">
|
9
|
+
<title><%= @subject %></title>
|
10
|
+
<style type="text/css">
|
11
|
+
<%= render 'layouts/maktoub/styles' %>
|
12
|
+
</style>
|
13
|
+
</head>
|
14
|
+
<body leftmargin="0" marginwidth="0" topmargin="0" marginheight="0" offset="0">
|
15
|
+
<center>
|
16
|
+
<table border="0" cellpadding="0" cellspacing="0" height="100%" width="100%" id="backgroundTable">
|
17
|
+
<tr>
|
18
|
+
<td align="center" valign="top">
|
19
|
+
<!-- // Begin Template Preheader \\ -->
|
20
|
+
<table border="0" cellpadding="10" cellspacing="0" width="600" id="templatePreheader">
|
21
|
+
<tr>
|
22
|
+
<td valign="top" class="preheaderContent">
|
23
|
+
|
24
|
+
<!-- // Begin Module: Standard Preheader \ -->
|
25
|
+
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
26
|
+
<tr>
|
27
|
+
<td valign="top">
|
28
|
+
<div>
|
29
|
+
<%= yield(:teaser) %>
|
30
|
+
</div>
|
31
|
+
</td>
|
32
|
+
|
33
|
+
<%- unless @archive %>
|
34
|
+
<td valign="top" width="190">
|
35
|
+
<div>
|
36
|
+
<%= @template %>
|
37
|
+
Is this email not displaying correctly?<br /><%= link_to "View it in your browser", newsletter_url(@newsletter_name), target: "_blank" %>.
|
38
|
+
</div>
|
39
|
+
</td>
|
40
|
+
<%- end %>
|
41
|
+
</tr>
|
42
|
+
</table>
|
43
|
+
<!-- // End Module: Standard Preheader \ -->
|
44
|
+
|
45
|
+
</td>
|
46
|
+
</tr>
|
47
|
+
</table>
|
48
|
+
<!-- // End Template Preheader \\ -->
|
49
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateContainer">
|
50
|
+
<tr>
|
51
|
+
<td align="center" valign="top">
|
52
|
+
<!-- // Begin Template Header \\ -->
|
53
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateHeader">
|
54
|
+
<tr>
|
55
|
+
<td class="headerContent">
|
56
|
+
|
57
|
+
<!-- // Begin Module: Standard Header Image \\ -->
|
58
|
+
<% img = image_tag Maktoub.logo, :style => "max-width:600px", :id => "headerImage campaign-icon", :alt => Maktoub.app_name %>
|
59
|
+
<%= link_to img, Maktoub.home_url, :target => "_blank" %>
|
60
|
+
<!-- // End Module: Standard Header Image \\ -->
|
61
|
+
<hr />
|
62
|
+
</td>
|
63
|
+
</tr>
|
64
|
+
</table>
|
65
|
+
<!-- // End Template Header \\ -->
|
66
|
+
</td>
|
67
|
+
</tr>
|
68
|
+
<tr>
|
69
|
+
<td align="center" valign="top">
|
70
|
+
<!-- // Begin Template Body \\ -->
|
71
|
+
<table border="0" cellpadding="0" cellspacing="0" width="600" id="templateBody">
|
72
|
+
<tr>
|
73
|
+
<td valign="top" class="bodyContent">
|
74
|
+
|
75
|
+
<!-- // Begin Module: Standard Content \\ -->
|
76
|
+
<table border="0" cellpadding="20" cellspacing="0" width="100%">
|
77
|
+
<tr>
|
78
|
+
<td valign="top">
|
79
|
+
<div mc:edit="std_content00">
|
80
|
+
<%= yield %>
|
81
|
+
</div>
|
82
|
+
</td>
|
83
|
+
</tr>
|
84
|
+
</table>
|
85
|
+
<!-- // End Module: Standard Content \\ -->
|
86
|
+
|
87
|
+
</td>
|
88
|
+
</tr>
|
89
|
+
</table>
|
90
|
+
<!-- // End Template Body \\ -->
|
91
|
+
</td>
|
92
|
+
</tr>
|
93
|
+
<tr>
|
94
|
+
<td align="center" valign="top">
|
95
|
+
<!-- // Begin Template Footer \\ -->
|
96
|
+
<table border="0" cellpadding="10" cellspacing="0" width="600" id="templateFooter">
|
97
|
+
<tr>
|
98
|
+
<td valign="top" class="footerContent">
|
99
|
+
|
100
|
+
<!-- // Begin Module: Standard Footer \\ -->
|
101
|
+
<table border="0" cellpadding="10" cellspacing="0" width="100%">
|
102
|
+
<tr>
|
103
|
+
<td colspan="2" valign="middle" id="social">
|
104
|
+
<div mc:edit="std_social">
|
105
|
+
|
106
|
+
<% unless Maktoub.twitter_url.blank? %>
|
107
|
+
<%= link_to 'follow on Twitter', Maktoub.twitter_url, :target => "_blank" %>
|
108
|
+
<% end %>
|
109
|
+
<% unless Maktoub.facebook_url.blank? %>
|
110
|
+
|
|
111
|
+
<%= link_to 'friend on Facebook', Maktoub.facebook_url, :target => "_blank" %>
|
112
|
+
<% end %>
|
113
|
+
<% unless Maktoub.google_plus_url.blank? %>
|
114
|
+
|
|
115
|
+
<%= link_to 'follow on Google+', Maktoub.google_plus_url, :target => "_blank" %>
|
116
|
+
<% end %>
|
117
|
+
|
118
|
+
</div>
|
119
|
+
</td>
|
120
|
+
</tr>
|
121
|
+
<tr>
|
122
|
+
<td valign="top" width="350">
|
123
|
+
<div mc:edit="std_footer">
|
124
|
+
<em>Copyright © <%= Time.now.year %> <%= Maktoub.app_name %>, All rights reserved.</em>
|
125
|
+
<br />
|
126
|
+
<em>You are receiving this email because you opted in at our website <%= link_to Maktoub.home_url, Maktoub.home_url, :target => "_blank" %>.</em>
|
127
|
+
<br />
|
128
|
+
<%- unless @archive %>
|
129
|
+
<%# we are not including mailing addresses %>
|
130
|
+
<%#<br /><strong>Our mailing address is:</strong><br /> %>
|
131
|
+
<%# %>
|
132
|
+
<%- end %>
|
133
|
+
</div>
|
134
|
+
</td>
|
135
|
+
|
136
|
+
</tr>
|
137
|
+
<tr>
|
138
|
+
<td colspan="2" valign="middle" id="utility">
|
139
|
+
<div>
|
140
|
+
<%= link_to 'update subscription preferences', Maktoub.subscription_preferences_url, :target => "_blank" %>
|
141
|
+
<%- if Maktoub.unsubscribe_method %>
|
142
|
+
| <%= link_to 'unsubscribe', edit_subscribers_url, :target => "_blank", :rel => "nofollow" %>
|
143
|
+
|
144
|
+
<% end %>
|
145
|
+
</div>
|
146
|
+
</td>
|
147
|
+
</tr>
|
148
|
+
</table>
|
149
|
+
<!-- // End Module: Standard Footer \\ -->
|
150
|
+
|
151
|
+
</td>
|
152
|
+
</tr>
|
153
|
+
</table>
|
154
|
+
<!-- // End Template Footer \\ -->
|
155
|
+
</td>
|
156
|
+
</tr>
|
157
|
+
</table>
|
158
|
+
<br />
|
159
|
+
</td>
|
160
|
+
</tr>
|
161
|
+
</table>
|
162
|
+
</center>
|
163
|
+
</body>
|
164
|
+
</html>
|
165
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<h1>Unsubscribe from newsletter</h1>
|
2
|
+
|
3
|
+
<%= form_tag subscribers_path, :method => :put do |f| %>
|
4
|
+
<p>
|
5
|
+
<%= label :subscribers, 'Email', :for => 'email' %>
|
6
|
+
<br/>
|
7
|
+
<%- if @message %>
|
8
|
+
<div style="color:red;"><%= @message %></div>
|
9
|
+
<%- end %>
|
10
|
+
<%= text_field :subscribers, 'email', {:type => "email", :id => 'email', :name => 'email'} %>
|
11
|
+
<br />
|
12
|
+
</p>
|
13
|
+
<p>
|
14
|
+
<%= button_tag 'submit', :type => 'submit' %>
|
15
|
+
</o>
|
16
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<h1>Unsubscribe successful</h1>
|
data/config/routes.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# Maktoub.from = "Test Sender <maktoub@example.com>" # the email the newsletter is sent from
|
2
|
+
# Maktoub.twitter_url = "http://twitter.com/#!/twitter" # your twitter page
|
3
|
+
# Maktoub.facebook_url = "http://www.facebook.com/facebook" # your facebook oage
|
4
|
+
# Maktoub.subscription_preferences_url = "http://example.com/manage_subscriptions" #subscribers management url
|
5
|
+
# Maktoub.logo = "logo.jpg" # path to your logo asset
|
6
|
+
# Maktoub.home_domain = "example.com" # your domain
|
7
|
+
# Maktoub.app_name = "Maktoub" # your app name
|
8
|
+
# Maktoub.unsubscribe_method = "unsubscribe" # method to call from unsubscribe link (doesn't include link by default)
|
9
|
+
|
10
|
+
# pass a block to subscribers_extractor that returns an object that reponds to :name and :email
|
11
|
+
# (fields can be configured as shown below)
|
12
|
+
|
13
|
+
# require "ostruct"
|
14
|
+
# Maktoub.subscribers_extractor do
|
15
|
+
# (1..5).map do |i|
|
16
|
+
# users << OpenStruct.new({name: "tester#{i}", email: "test#{i}@example.com"})
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
|
20
|
+
# uncomment lines below to change subscriber fields that contain email and
|
21
|
+
# Maktoub.email_field = :address
|
22
|
+
# Maktoub.name_field = :nickname
|
data/lib/maktoub.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require "maktoub/engine"
|
2
|
+
|
3
|
+
module Maktoub
|
4
|
+
class << self
|
5
|
+
attr_accessor :from,
|
6
|
+
:twitter_url,
|
7
|
+
:facebook_url,
|
8
|
+
:google_plus_url,
|
9
|
+
:subscription_preferences_url,
|
10
|
+
:logo,
|
11
|
+
:home_domain,
|
12
|
+
:app_name,
|
13
|
+
:unsubscribe_method
|
14
|
+
|
15
|
+
attr_writer :email_field, :name_field
|
16
|
+
|
17
|
+
def email_field
|
18
|
+
@email_field || :email
|
19
|
+
end
|
20
|
+
|
21
|
+
def name_field
|
22
|
+
@name_field || :name
|
23
|
+
end
|
24
|
+
|
25
|
+
def subscribers
|
26
|
+
@subscribers.call
|
27
|
+
end
|
28
|
+
|
29
|
+
def subscribers_extractor (&block)
|
30
|
+
@subscribers = Proc.new &block
|
31
|
+
end
|
32
|
+
|
33
|
+
def unsubscribe(email)
|
34
|
+
subscribers.select do |s|
|
35
|
+
s.send(email_field) == email
|
36
|
+
end.each do |s|
|
37
|
+
s.send(unsubscribe_method) if unsubscribe_method
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def home_url
|
42
|
+
"http://" + home_domain
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
namespace :maktoub do
|
2
|
+
desc "send :newsletter to the configured from address"
|
3
|
+
task :test, [:newsletter] => [:environment] do |t, args|
|
4
|
+
if Maktoub::NewsletterMailer.method_defined? :delay
|
5
|
+
Maktoub::NewsletterMailer.delay(:priority => 5, :queue => 'maktoub').publish(args[:newsletter], :email => Maktoub.from, :name => 'Tester')
|
6
|
+
puts "delayed #{Maktoub.from}"
|
7
|
+
else
|
8
|
+
Maktoub::NewsletterMailer.publish(args[:newsletter], :email => Maktoub.from, :name => 'Joe Tester').deliver
|
9
|
+
puts "delivered #{Maktoub.from}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "send :newsletter to all subscribers"
|
14
|
+
task :mail, [:newsletter] => [:environment] do |t, args|
|
15
|
+
puts "starting..."
|
16
|
+
messages = Maktoub.subscribers.map do |u|
|
17
|
+
if Maktoub::NewsletterMailer.method_defined? :delay
|
18
|
+
Maktoub::NewsletterMailer.delay(:priority => 5, :queue => 'maktoub').publish(args[:newsletter], :email => u.send(Maktoub.email_field), :name => u.send(Maktoub.name_field))
|
19
|
+
"delayed #{u.send Maktoub.email_field}"
|
20
|
+
else
|
21
|
+
Maktoub::NewsletterMailer.publish(args[:newsletter], :email => u.send(Maktoub.email_field), :name => u.send(Maktoub.name_field)).deliver
|
22
|
+
"delivered #{u.send Maktoub.email_field}"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
puts "#{messages.length} messages"
|
26
|
+
puts messages.join("\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: resque-maktoub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.5
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Zaid Zawaideh
|
9
|
+
- Rodi Alessandro
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
12
|
+
cert_chain: []
|
13
|
+
date: 2013-01-23 00:00:00.000000000 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rails
|
17
|
+
requirement: !ruby/object:Gem::Requirement
|
18
|
+
none: false
|
19
|
+
requirements:
|
20
|
+
- - ! '>='
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 3.1.1
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
none: false
|
27
|
+
requirements:
|
28
|
+
- - ! '>='
|
29
|
+
- !ruby/object:Gem::Version
|
30
|
+
version: 3.1.1
|
31
|
+
- !ruby/object:Gem::Dependency
|
32
|
+
name: premailer
|
33
|
+
requirement: !ruby/object:Gem::Requirement
|
34
|
+
none: false
|
35
|
+
requirements:
|
36
|
+
- - ! '>='
|
37
|
+
- !ruby/object:Gem::Version
|
38
|
+
version: '0'
|
39
|
+
type: :runtime
|
40
|
+
prerelease: false
|
41
|
+
version_requirements: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ! '>='
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: nokogiri
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
|
+
none: false
|
59
|
+
requirements:
|
60
|
+
- - ! '>='
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: resque_mailer
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ! '>='
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: '0'
|
71
|
+
type: :runtime
|
72
|
+
prerelease: false
|
73
|
+
version_requirements: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ! '>='
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
- !ruby/object:Gem::Dependency
|
80
|
+
name: sqlite3
|
81
|
+
requirement: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ! '>='
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
type: :development
|
88
|
+
prerelease: false
|
89
|
+
version_requirements: !ruby/object:Gem::Requirement
|
90
|
+
none: false
|
91
|
+
requirements:
|
92
|
+
- - ! '>='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: rspec-rails
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
none: false
|
99
|
+
requirements:
|
100
|
+
- - ! '>='
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
type: :development
|
104
|
+
prerelease: false
|
105
|
+
version_requirements: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: A simple asynchronousnewsletter engine for rails powered by resque.
|
112
|
+
email:
|
113
|
+
- coorasse@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- app/controllers/maktoub/archives_controller.rb
|
119
|
+
- app/controllers/maktoub/subscribers_controller.rb
|
120
|
+
- app/controllers/maktoub/application_controller.rb
|
121
|
+
- app/assets/stylesheets/maktoub/application.css
|
122
|
+
- app/assets/stylesheets/maktoub/archives.css
|
123
|
+
- app/assets/javascripts/maktoub/archives.js
|
124
|
+
- app/assets/javascripts/maktoub/application.js
|
125
|
+
- app/mailers/maktoub/newsletter_mailer.rb
|
126
|
+
- app/helpers/maktoub/application_helper.rb
|
127
|
+
- app/helpers/maktoub/archives_helper.rb
|
128
|
+
- app/views/layouts/maktoub/application.html.erb
|
129
|
+
- app/views/layouts/maktoub/_styles.erb
|
130
|
+
- app/views/layouts/maktoub/newsletter_mailer.erb
|
131
|
+
- app/views/maktoub/newsletters/readme.erb
|
132
|
+
- app/views/maktoub/subscribers/edit.html.erb
|
133
|
+
- app/views/maktoub/subscribers/update.html.erb
|
134
|
+
- config/routes.rb
|
135
|
+
- lib/tasks/maktoub_tasks.rake
|
136
|
+
- lib/generators/maktoub/USAGE
|
137
|
+
- lib/generators/maktoub/templates/maktoub.rb
|
138
|
+
- lib/generators/maktoub/config_generator.rb
|
139
|
+
- lib/maktoub/version.rb
|
140
|
+
- lib/maktoub/engine.rb
|
141
|
+
- lib/maktoub.rb
|
142
|
+
- MIT-LICENSE
|
143
|
+
- Rakefile
|
144
|
+
- README.rdoc
|
145
|
+
homepage: http://www.rodialessandro.id
|
146
|
+
licenses: []
|
147
|
+
post_install_message:
|
148
|
+
rdoc_options: []
|
149
|
+
require_paths:
|
150
|
+
- lib
|
151
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
152
|
+
none: false
|
153
|
+
requirements:
|
154
|
+
- - ! '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
158
|
+
none: false
|
159
|
+
requirements:
|
160
|
+
- - ! '>='
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 1.8.24
|
166
|
+
signing_key:
|
167
|
+
specification_version: 3
|
168
|
+
summary: A simple asynchronous newsletter engine for rails powered by resque.
|
169
|
+
test_files: []
|