snails 0.3.6 → 0.4.3
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 +4 -4
- data/lib/snails.rb +6 -1
- data/lib/snails/app.rb +17 -8
- data/lib/snails/mailer.rb +100 -27
- data/lib/snails/markdown.rb +53 -0
- data/lib/snails/tasks.rb +2 -4
- data/lib/snails/util.rb +6 -10
- data/snails.gemspec +2 -1
- metadata +17 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 483517cd1b55bc5273ebb004bb9ef69a8cd6191de4be897c3d9f2c168ea13f4f
|
|
4
|
+
data.tar.gz: 1730ce09810faafc5802833ab4f38fb103e8dae059b9cfb51b85335893fb7f09
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e104410a7d4f8eea1370a583d13e4f23cefd043bc78f12027b5fea7063a87285c2cbeb89a1ab8c9a43e7a90d582b3b397528f1c483df2db60cf7dc654f66aba7
|
|
7
|
+
data.tar.gz: dfe0ae0b0116f29c71907e35a38548d3d28af693e7dbf824b29f6e467ddab841d588c6f573b238c3e50d420bae649f81fca9efb73cb3709ac158eb121dae45e3
|
data/lib/snails.rb
CHANGED
|
@@ -41,5 +41,10 @@ module Snails
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
+
# sinatra/activerecord only 'reads' RACK_ENV, so make sure it is set
|
|
45
|
+
ENV['RACK_ENV'] ||= ENV['RAILS_ENV']
|
|
46
|
+
|
|
44
47
|
require 'snails/app' unless Snails.env.test?
|
|
45
|
-
|
|
48
|
+
unless ENV['SILENT']
|
|
49
|
+
puts "Loaded #{Snails.env} environment. (#{Time.now.to_s})"
|
|
50
|
+
end
|
data/lib/snails/app.rb
CHANGED
|
@@ -13,7 +13,7 @@ module Snails
|
|
|
13
13
|
module All
|
|
14
14
|
|
|
15
15
|
# usage:
|
|
16
|
-
#
|
|
16
|
+
#
|
|
17
17
|
# class App < Snails::App
|
|
18
18
|
# register Snails::All
|
|
19
19
|
# end
|
|
@@ -99,7 +99,7 @@ module Snails
|
|
|
99
99
|
|
|
100
100
|
cwd = Pathname.new(Dir.pwd)
|
|
101
101
|
app.set :sprockets, Sprockets::Environment.new(cwd)
|
|
102
|
-
app.set :digest_assets, false
|
|
102
|
+
app.set :digest_assets, false
|
|
103
103
|
app.set :assets_prefix, app.setting(:assets_prefix, '/assets') # URL
|
|
104
104
|
app.set :assets_paths, app.setting(:assets_paths, %w(assets)) # source files
|
|
105
105
|
app.set :assets_public_path, app.setting(:assets_public_path, cwd.join('public', 'assets')) # output dir
|
|
@@ -308,8 +308,8 @@ module Snails
|
|
|
308
308
|
label = options[:label] || field.to_s.gsub('_', ' ').capitalize
|
|
309
309
|
example = options[:example] ? "<small class='example'>#{options[:example]}</small>" : ''
|
|
310
310
|
|
|
311
|
-
id = "#{get_model_name(object).downcase}_#{options[:key] || field}"
|
|
312
|
-
name = "#{get_model_name(object).downcase}[#{field}]"
|
|
311
|
+
id = options[:id] || "#{get_model_name(object).downcase}_#{options[:key] || field}"
|
|
312
|
+
name = options[:name] || "#{get_model_name(object).downcase}[#{field}]"
|
|
313
313
|
label = options[:label] == false ? '' : "<label for='#{id}'>#{label}#{example}</label>\n"
|
|
314
314
|
|
|
315
315
|
@tabindex = @tabindex ? @tabindex + 1 : 1
|
|
@@ -353,6 +353,14 @@ module Snails
|
|
|
353
353
|
erb(view_name.to_sym, { layout: layout }.merge(opts))
|
|
354
354
|
end
|
|
355
355
|
|
|
356
|
+
def show_date(date)
|
|
357
|
+
date ? date.strftime("%d de %b, %Y") : ''
|
|
358
|
+
end
|
|
359
|
+
|
|
360
|
+
def show_time(time)
|
|
361
|
+
time ? time.strftime("%d de %b, %Y a las %H:%M") : ''
|
|
362
|
+
end
|
|
363
|
+
|
|
356
364
|
#########################################
|
|
357
365
|
# pagination
|
|
358
366
|
|
|
@@ -381,7 +389,7 @@ module Snails
|
|
|
381
389
|
|
|
382
390
|
def self.registered(app)
|
|
383
391
|
app.set :sessions, {
|
|
384
|
-
key: app.setting(:session_key, 'snails.session'),
|
|
392
|
+
key: app.setting(:session_key, 'snails.session'),
|
|
385
393
|
path: app.setting(:session_path, '/'),
|
|
386
394
|
expire_after: app.setting(:session_expire_after, 2592000), # one month in seconds
|
|
387
395
|
secret: app.session_secret # uses previous set :session_secret or generates one
|
|
@@ -411,16 +419,17 @@ module Snails
|
|
|
411
419
|
enable :logging
|
|
412
420
|
|
|
413
421
|
use Rack::CommonLogger, Snails.logger
|
|
414
|
-
use Rack::Static, urls: static_paths, root: 'public' unless Snails.env.production?
|
|
422
|
+
use Rack::Static, urls: static_paths, root: 'public' unless Snails.env.production?
|
|
415
423
|
|
|
416
424
|
configure :production, :staging do
|
|
417
|
-
set :raise_errors,
|
|
425
|
+
set :raise_errors, false
|
|
418
426
|
set :dump_errors, false
|
|
427
|
+
set :show_exceptions, false
|
|
419
428
|
end
|
|
420
429
|
|
|
421
430
|
configure :development do
|
|
422
431
|
set :raise_errors, true
|
|
423
|
-
set :dump_errors,
|
|
432
|
+
set :dump_errors, true
|
|
424
433
|
set :show_exceptions, true
|
|
425
434
|
set :log_level, Logger::DEBUG
|
|
426
435
|
end
|
data/lib/snails/mailer.rb
CHANGED
|
@@ -12,32 +12,28 @@ module Snails
|
|
|
12
12
|
|
|
13
13
|
@queue = :emails
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if key = mail_config.dig(:dkim, :private_key) and File.exist?(key)
|
|
19
|
-
mail_config[:dkim][:private_key] = IO.read(key)
|
|
20
|
-
elsif mail_config[:dkim]
|
|
21
|
-
puts "Private key for DKIM not found! Disabling..."
|
|
22
|
-
mail_config.delete(:dkim)
|
|
23
|
-
end
|
|
15
|
+
# class Bounce < StandardError; end
|
|
16
|
+
# class SoftBounce < Bounce; end
|
|
17
|
+
# class HardBounce < Bounce; end
|
|
24
18
|
|
|
25
|
-
|
|
26
|
-
@debug = mail_config[:debug]
|
|
19
|
+
def initialize(opts)
|
|
27
20
|
@from_email = opts[:from] or raise ":from required"
|
|
28
21
|
@base_subject = opts[:base_subject] || ''
|
|
29
22
|
@views = opts[:views] || Snails.root.join('lib', 'views')
|
|
30
23
|
@logfile = opts[:logfile] # || Snails.root.join('log', 'mailer.log')
|
|
24
|
+
|
|
25
|
+
backend_name = opts[:backend_name] || 'TestBackend'
|
|
26
|
+
@backend = self.class.backends[backend_name].new(opts[:backend_options])
|
|
31
27
|
end
|
|
32
28
|
|
|
33
29
|
def email(name, &block)
|
|
34
30
|
define_singleton_method(name) do |*args|
|
|
35
|
-
instance_exec(*args, &block)
|
|
31
|
+
instance_exec(*args, &block)
|
|
36
32
|
end
|
|
37
33
|
end
|
|
38
34
|
|
|
39
35
|
def helpers(&block)
|
|
40
|
-
instance_eval(&block)
|
|
36
|
+
instance_eval(&block)
|
|
41
37
|
end
|
|
42
38
|
|
|
43
39
|
def perform(method, *args)
|
|
@@ -81,50 +77,127 @@ A <%= @exception.class %> occurred in <%= @url %>:
|
|
|
81
77
|
|
|
82
78
|
private
|
|
83
79
|
|
|
84
|
-
def render(
|
|
85
|
-
|
|
80
|
+
def render(view_path, layout_lath = nil)
|
|
81
|
+
view = File.read(File.join(@views, "#{view_path}.erb"))
|
|
82
|
+
if layout_path
|
|
83
|
+
layout = File.read(File.join(@views, "#{layout_path}.erb"))
|
|
84
|
+
render_erb(layout) { render_erb(view) }
|
|
85
|
+
else
|
|
86
|
+
render_erb(view)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def render_erb(template)
|
|
86
91
|
ERB.new(template).result(binding)
|
|
87
92
|
end
|
|
88
93
|
|
|
89
94
|
def partial(name)
|
|
90
95
|
partial_name = name.to_s["/"] ? name.to_s.reverse.sub("/", "_/").reverse : "_#{name}"
|
|
91
|
-
render
|
|
96
|
+
render(partial_name)
|
|
92
97
|
end
|
|
93
98
|
|
|
94
99
|
def logger
|
|
95
100
|
@logger ||= @logfile ? Logger.new(@logfile) : Snails.logger
|
|
96
101
|
end
|
|
97
102
|
|
|
98
|
-
def send_email(from:
|
|
103
|
+
def send_email(from: @from_email, to:, subject:, body: nil, template: nil, layout: nil, html_body: nil, html_template: nil, html_layout: nil, message_id: nil, return_path: nil, list_unsubscribe: nil)
|
|
99
104
|
raise "No recipient given for mail: #{subject}!" if to.blank?
|
|
100
105
|
|
|
101
106
|
message = {
|
|
102
107
|
to: to,
|
|
103
|
-
from: from
|
|
104
|
-
subject: @base_subject + subject
|
|
108
|
+
from: from,
|
|
109
|
+
subject: @base_subject + subject
|
|
105
110
|
}
|
|
106
111
|
|
|
112
|
+
raise "Blank from" if message[:from].blank?
|
|
113
|
+
raise "Blank to" if message[:to].blank?
|
|
114
|
+
|
|
107
115
|
if body or template
|
|
108
|
-
message[:body] = template ? render(template) : body
|
|
116
|
+
message[:body] = template ? render(template, layout) : body
|
|
109
117
|
end
|
|
110
118
|
|
|
111
119
|
if html_body or html_template
|
|
112
|
-
message[:html_body] = html_template ? render(html_template) : html_body
|
|
120
|
+
message[:html_body] = html_template ? render(html_template, html_layout) : html_body
|
|
113
121
|
end
|
|
114
122
|
|
|
115
123
|
message[:message_id] = message_id if message_id
|
|
116
124
|
message[:return_path] = return_path if return_path
|
|
117
125
|
message[:list_unsubscribe] = list_unsubscribe if list_unsubscribe
|
|
118
126
|
|
|
119
|
-
logger.info "[#{to}] Delivering: #{subject}"
|
|
120
|
-
|
|
121
|
-
|
|
127
|
+
logger.info "[#{to}] Delivering: #{subject}"
|
|
128
|
+
@backend.deliver(message)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
alias_method :deliver, :send_email
|
|
132
|
+
|
|
133
|
+
class Backend
|
|
134
|
+
def deliver(email, options = {})
|
|
135
|
+
raise "Please redefine in subclass"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def deliver_many(emails, options = {})
|
|
139
|
+
emails.map { |e| deliver(e, options) }
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class Tuktuk < Backend
|
|
144
|
+
def initialize(config = {})
|
|
145
|
+
@debug = config[:debug]
|
|
146
|
+
|
|
147
|
+
if key = config.dig(:dkim, :private_key) and File.exist?(key)
|
|
148
|
+
config[:dkim][:private_key] = IO.read(key)
|
|
149
|
+
elsif config[:dkim]
|
|
150
|
+
puts "Private key for DKIM not found! Disabling..."
|
|
151
|
+
config.delete(:dkim)
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
Tuktuk.options = config
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def deliver(email, options = {})
|
|
158
|
+
debug = @debug.nil? ? !Snails.env.production? : @debug # if debug isn't set, determine based on env
|
|
159
|
+
resp, email = Tuktuk.deliver(email, debug: debug)
|
|
160
|
+
|
|
161
|
+
if resp.is_a?(Tuktuk::Bounce)
|
|
162
|
+
logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}"
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
return resp, email
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def deliver_many(emails, options = {})
|
|
169
|
+
Tuktuk.deliver_many(emails, options)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
class Mailgun < Backend
|
|
174
|
+
|
|
175
|
+
def initialize(api_key:, domain_name:)
|
|
176
|
+
@key = api_key
|
|
177
|
+
@url = "https://api.mailgun.net/v3/#{domain_name}/messages"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def deliver(email, options = {})
|
|
181
|
+
raise "No body!" if email[:body].nil?
|
|
182
|
+
|
|
183
|
+
data = {
|
|
184
|
+
from: email[:from],
|
|
185
|
+
to: email[:to],
|
|
186
|
+
subject: email[:subject],
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
data[:text] = email[:body] if email[:body]
|
|
190
|
+
data[:html] = email[:html_body] if email[:html_body]
|
|
191
|
+
|
|
192
|
+
if data[:text].blank? && data[:html].blank?
|
|
193
|
+
raise ArgumentError, "Either text or html required"
|
|
194
|
+
end
|
|
122
195
|
|
|
123
|
-
|
|
124
|
-
|
|
196
|
+
opts = { username: 'api', password: @key }
|
|
197
|
+
resp = Dagger.post(@url, data, opts)
|
|
198
|
+
resp.ok? ? [resp.data, data[:to]] : nil
|
|
125
199
|
end
|
|
126
200
|
|
|
127
|
-
return resp, email
|
|
128
201
|
end
|
|
129
202
|
|
|
130
203
|
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
begin
|
|
2
|
+
require 'rinku'
|
|
3
|
+
require 'kramdown'
|
|
4
|
+
require 'sanitize'
|
|
5
|
+
|
|
6
|
+
module Snails
|
|
7
|
+
module Markdown
|
|
8
|
+
|
|
9
|
+
MARKDOWN_OPTS = {
|
|
10
|
+
input: 'GFM',
|
|
11
|
+
enable_coderay: true,
|
|
12
|
+
parse_block_html: false,
|
|
13
|
+
line_width: 72,
|
|
14
|
+
coderay_tab_width: 2,
|
|
15
|
+
coderay_line_numbers: nil,
|
|
16
|
+
coderay_default_lang: 'bash',
|
|
17
|
+
coderay_css: :class
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
SANITIZE_OPTS = Sanitize::Config::RELAXED
|
|
21
|
+
|
|
22
|
+
SANITIZE_OPTS[:elements] = %w(
|
|
23
|
+
p br a span sub sup strong em div hr abbr
|
|
24
|
+
ul ol li
|
|
25
|
+
blockquote pre code kbd
|
|
26
|
+
h1 h2 h3 h4 h5 h6
|
|
27
|
+
img object param del
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
SANITIZE_OPTS[:attributes] = {
|
|
31
|
+
:all => ['class', 'style', 'title', 'id'],
|
|
32
|
+
'a' => ['href', 'rel', 'name'],
|
|
33
|
+
'img' => ['src', 'title', 'alt', 'width', 'height']
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
SANITIZE_OPTS[:add_attributes] = { 'a' => {'rel' => 'nofollow', 'target' => '_blank'} }
|
|
37
|
+
|
|
38
|
+
def render_markdown(str, options = {})
|
|
39
|
+
html = Kramdown::Document.new(str, MARKDOWN_OPTS).to_html
|
|
40
|
+
html = Rinku.auto_link(html, :urls)
|
|
41
|
+
Sanitize.clean(html, SANITIZE_OPTS)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
rescue LoadError => e
|
|
49
|
+
puts "Cannot load Snails's markdown lib. (#{e.class})"
|
|
50
|
+
puts "You need the `kramdown`, `rinku` and `sanitize` gems for this."
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
|
data/lib/snails/tasks.rb
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
require 'snails'
|
|
2
2
|
|
|
3
|
-
if defined?(Sinatra::ActiveRecordHelper)
|
|
3
|
+
if defined?(Sinatra::ActiveRecordHelper) or File.exist?(FileUtils.pwd + '/db/schema.rb')
|
|
4
4
|
require 'sinatra/activerecord/rake'
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
namespace :assets do
|
|
8
|
-
|
|
9
8
|
desc 'Precompiles assets'
|
|
10
9
|
task :precompile do
|
|
11
10
|
if Snails.apps.empty?
|
|
@@ -16,5 +15,4 @@ namespace :assets do
|
|
|
16
15
|
end
|
|
17
16
|
end
|
|
18
17
|
end
|
|
19
|
-
|
|
20
|
-
end
|
|
18
|
+
end
|
data/lib/snails/util.rb
CHANGED
|
@@ -6,16 +6,12 @@ module Snails
|
|
|
6
6
|
|
|
7
7
|
def self.minutes_in_words(min)
|
|
8
8
|
case min.to_i
|
|
9
|
-
when 0..1 then '
|
|
10
|
-
when 2..4 then '
|
|
11
|
-
when 5..14 then '
|
|
9
|
+
when 0..1 then 'un minuto'
|
|
10
|
+
when 2..4 then '5 minutos'
|
|
11
|
+
when 5..14 then '15 minutos'
|
|
12
12
|
when 15..29 then "media hora"
|
|
13
|
-
when 30..59 then "#{min}
|
|
14
|
-
when 60..
|
|
15
|
-
when 120..239 then '2 horas'
|
|
16
|
-
when 240..479 then '4 horas'
|
|
17
|
-
when 480..719 then '8 horas'
|
|
18
|
-
when 720..1439 then '12 horas'
|
|
13
|
+
when 30..59 then "#{min} min"
|
|
14
|
+
when 60..1439 then "#{(min/60).floor} horas"
|
|
19
15
|
when 1440..11519 then "#{(min/1440).floor} días"
|
|
20
16
|
when 11520..43199 then "#{(min/11520).floor} semanas"
|
|
21
17
|
when 43200..525599 then "#{(min/43200).floor} meses"
|
|
@@ -34,7 +30,7 @@ module Snails
|
|
|
34
30
|
if Time.now < self
|
|
35
31
|
# "#{str} más"
|
|
36
32
|
"en #{str}"
|
|
37
|
-
else
|
|
33
|
+
else
|
|
38
34
|
"hace #{str}"
|
|
39
35
|
end
|
|
40
36
|
end
|
data/snails.gemspec
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
Gem::Specification.new do |s|
|
|
5
5
|
s.name = "snails"
|
|
6
|
-
s.version = '0.3
|
|
6
|
+
s.version = '0.4.3'
|
|
7
7
|
s.platform = Gem::Platform::RUBY
|
|
8
8
|
s.authors = ['Tomás Pollak']
|
|
9
9
|
s.email = ['tomas@forkhq.com']
|
|
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
|
|
|
17
17
|
s.add_development_dependency "fuubar", '>= 2.3.2'
|
|
18
18
|
|
|
19
19
|
s.add_runtime_dependency "i18n", ">= 1.0.1"
|
|
20
|
+
s.add_runtime_dependency "activerecord", "< 6.0"
|
|
20
21
|
s.add_runtime_dependency "sinatra-contrib", ">= 2.0.3"
|
|
21
22
|
s.add_runtime_dependency "sinatra-activerecord", ">= 2.0.13"
|
|
22
23
|
s.add_runtime_dependency "sinatra-flash", ">= 0.3.0"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: snails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3
|
|
4
|
+
version: 0.4.3
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tomás Pollak
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2020-10-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -72,6 +72,20 @@ dependencies:
|
|
|
72
72
|
- - ">="
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
74
|
version: 1.0.1
|
|
75
|
+
- !ruby/object:Gem::Dependency
|
|
76
|
+
name: activerecord
|
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - "<"
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '6.0'
|
|
82
|
+
type: :runtime
|
|
83
|
+
prerelease: false
|
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - "<"
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '6.0'
|
|
75
89
|
- !ruby/object:Gem::Dependency
|
|
76
90
|
name: sinatra-contrib
|
|
77
91
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -159,6 +173,7 @@ files:
|
|
|
159
173
|
- lib/snails.rb
|
|
160
174
|
- lib/snails/app.rb
|
|
161
175
|
- lib/snails/mailer.rb
|
|
176
|
+
- lib/snails/markdown.rb
|
|
162
177
|
- lib/snails/rspec.rb
|
|
163
178
|
- lib/snails/tasks.rb
|
|
164
179
|
- lib/snails/util.rb
|