snails 0.3.6 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 33aac0b5a88a59ea685e3fc896dbcdc7ee369b486b3802ceccd3b1e860d38db1
4
- data.tar.gz: 6b6612a3054b980f46c0375967ee02204c11982d11179a4ef500bd0e1b94aeda
3
+ metadata.gz: 483517cd1b55bc5273ebb004bb9ef69a8cd6191de4be897c3d9f2c168ea13f4f
4
+ data.tar.gz: 1730ce09810faafc5802833ab4f38fb103e8dae059b9cfb51b85335893fb7f09
5
5
  SHA512:
6
- metadata.gz: e7b51335c3a06e4a9d98bd6fc519a7ed72137c6249d940a5394acb9c10e4e167a02b6f9b8c09cdb756b8d0e4263602dd60e7b925c266993cac8d1fdbd2af825e
7
- data.tar.gz: f60ec8d7471561c0f7b0db13a8ad9eef8def39cc285475bd907714a638614cdc615977042fa416121be61fb99403e4b1a956ec45cf6ce7f0de917d986602d15c
6
+ metadata.gz: e104410a7d4f8eea1370a583d13e4f23cefd043bc78f12027b5fea7063a87285c2cbeb89a1ab8c9a43e7a90d582b3b397528f1c483df2db60cf7dc654f66aba7
7
+ data.tar.gz: dfe0ae0b0116f29c71907e35a38548d3d28af693e7dbf824b29f6e467ddab841d588c6f573b238c3e50d420bae649f81fca9efb73cb3709ac158eb121dae45e3
@@ -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
- puts "Loaded #{Snails.env} environment."
48
+ unless ENV['SILENT']
49
+ puts "Loaded #{Snails.env} environment. (#{Time.now.to_s})"
50
+ end
@@ -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, true
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, false
432
+ set :dump_errors, true
424
433
  set :show_exceptions, true
425
434
  set :log_level, Logger::DEBUG
426
435
  end
@@ -12,32 +12,28 @@ module Snails
12
12
 
13
13
  @queue = :emails
14
14
 
15
- def initialize(opts)
16
- mail_config = (opts[:smtp] || opts[:mail]) or raise ":smtp options missing"
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
- Tuktuk.options = mail_config
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(view)
85
- template = File.read(File.join(@views, "#{view}.erb"))
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 partial_name
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: nil, to:, subject:, body: nil, template: nil, html_body: nil, html_template: nil, message_id: nil, return_path: nil, list_unsubscribe: nil)
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 || @from_email,
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
- debug = @debug.nil? ? !Snails.env.production? : @debug # if debug isn't set, determine based on env
121
- resp, email = Tuktuk.deliver(message, debug: debug)
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
- if resp.is_a?(Tuktuk::Bounce)
124
- logger.info "[#{to}] Email bounced! [#{resp.code}] #{resp.message}"
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
+
@@ -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
@@ -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 'menos de un min'
10
- when 2..4 then 'menos de 5 min'
11
- when 5..14 then 'menos de 15 min'
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} minutos"
14
- when 60..119 then '1 hora'
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
@@ -3,7 +3,7 @@
3
3
 
4
4
  Gem::Specification.new do |s|
5
5
  s.name = "snails"
6
- s.version = '0.3.6'
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.6
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: 2019-02-10 00:00:00.000000000 Z
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