gemstack-mail 0.2.5 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6b803e84a27741f520f77c1155ea6ecf4c4ce640f31629e2c02b3dd5545141bb
4
- data.tar.gz: 4bcdcaef45a111d597daa07b67070ad86ea7ae278ae6a6f1936941609c6227a6
3
+ metadata.gz: d94ff9810f672d1d382bdf463338115eb1434f6d93e7cdfa31a31246c832a10d
4
+ data.tar.gz: b1f583a5d37f8db64de0b8492ec05cd9d028466493f01404dae1a668ac1a2744
5
5
  SHA512:
6
- metadata.gz: 3f6c84b19b4e8c18d8aaf50033578a8dc5db2e78905db028bad1ba7f8ab59c8001bdfac7b59ca26745bc49a6557e9a39d419e9ce3445ba178a6d161d443b77fc
7
- data.tar.gz: 8aa80738083852405125e756042d133c34c43990a7b3314c0f2ea2c4d5838a73e2d5abdea8bbc471788353f25761c9cc917eb64c12687c50c320b0a3944177ca
6
+ metadata.gz: 9b77854e54d27d67c8be3be3b598ceec4c8cb05940b206b2a3cbc3f5276b526c7efa8505638512bac406115dd16a83682b408a2c49b31fece4e5d6d5dbe798af
7
+ data.tar.gz: 0ebbde8d59f1617602bfddae48019609af2d22511548de3e712f2fe938661a4dbb1d08f29c7a9093e6ca34b19050522d9b632e2eb59670f36c40a1aa2e0e1c00
data/CHANGELOG.md CHANGED
@@ -1,29 +1,5 @@
1
1
  # Changelog
2
2
 
3
- ## 0.2.5
3
+ ## 0.3.0
4
4
 
5
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
6
-
7
- ## 0.2.4
8
-
9
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
10
-
11
- ## 0.2.3
12
-
13
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
14
-
15
- ## 0.2.2
16
-
17
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
18
-
19
- ## 0.2.1
20
-
21
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
22
-
23
- ## 0.2.0
24
-
25
- See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
26
-
27
- ## 0.1.0
28
-
29
- First release. See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
5
+ Merged into the gemstack gem; this version is a transition shim. See the [GemStack changelog](https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md).
data/README.md CHANGED
@@ -1,27 +1,13 @@
1
1
  # gemstack-mail
2
2
 
3
- GemStack mail: mailers, templates, SMTP/log/test delivery, deliver_later via jobs.
3
+ **Merged into [`gemstack`](https://rubygems.org/gems/gemstack) in GemStack 0.3.0.**
4
4
 
5
- Part of [GemStack](https://github.com/gemstack-rb/gemstack), a modular Ruby API framework for Next.js
6
- applications by [Adware Technologies](https://www.adwaretech.com). All GemStack gems are developed together in that repository and released with the same
7
- version.
5
+ This version is a transition shim: it depends on `gemstack` and loads `gemstack/mail`, so
6
+ Gemfiles that still list `gemstack-mail` keep working. To finish upgrading, remove `gem "gemstack-mail"`
7
+ from your Gemfile and make sure `config/app.rb` has `require "gemstack/mail"` (apps created with 0.3.0 do).
8
8
 
9
- ## Installation
10
-
11
- Optional module — `gemstack add auth`, or add it to the Gemfile:
12
-
13
- ```ruby
14
- gem "gemstack-mail", "~> 0.1"
15
- ```
16
-
17
- ## Documentation
18
-
19
- - [Guide](https://github.com/gemstack-rb/gemstack/blob/main/docs/mail.md)
20
- - [All guides](https://github.com/gemstack-rb/gemstack/tree/main/docs) ·
21
- [Architecture](https://github.com/gemstack-rb/gemstack/blob/main/ARCHITECTURE.md)
22
-
23
- Source, issues and pull requests: [gemstack-rb/gemstack](https://github.com/gemstack-rb/gemstack)
24
- (this gem lives in `gems/gemstack-mail`).
9
+ GemStack is a modular Ruby API framework for Next.js applications by
10
+ [Adware Technologies](https://www.adwaretech.com) — [gemstack-rb/gemstack](https://github.com/gemstack-rb/gemstack).
25
11
 
26
12
  ## License
27
13
 
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ # gemstack-mail is part of the gemstack gem since 0.3.0. This shim keeps Gemfiles
4
+ # that still list gemstack-mail working; remove the line from your Gemfile.
5
+ require "gemstack/mail"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gemstack-mail
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adware Technologies
@@ -11,47 +11,28 @@ cert_chain: []
11
11
  date: 1980-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: erubi
14
+ name: gemstack
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '1.13'
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.13'
27
- - !ruby/object:Gem::Dependency
28
- name: gemstack-core
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '='
19
+ version: 0.3.0
20
+ - - "<"
32
21
  - !ruby/object:Gem::Version
33
- version: 0.2.5
22
+ version: '1.0'
34
23
  type: :runtime
35
24
  prerelease: false
36
25
  version_requirements: !ruby/object:Gem::Requirement
37
26
  requirements:
38
- - - '='
27
+ - - ">="
39
28
  - !ruby/object:Gem::Version
40
- version: 0.2.5
41
- - !ruby/object:Gem::Dependency
42
- name: mail
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '2.9'
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
29
+ version: 0.3.0
30
+ - - "<"
53
31
  - !ruby/object:Gem::Version
54
- version: '2.9'
32
+ version: '1.0'
33
+ description: Since GemStack 0.3.0, gemstack-mail is part of the gemstack gem. This
34
+ version only depends on gemstack and loads gemstack/mail, so Gemfiles that still
35
+ list it keep working.
55
36
  email:
56
37
  - gemstack26@gmail.com
57
38
  executables: []
@@ -61,18 +42,19 @@ files:
61
42
  - CHANGELOG.md
62
43
  - LICENSE.txt
63
44
  - README.md
64
- - lib/gemstack/mail.rb
65
- - lib/gemstack/mail/delivery_job.rb
66
- - lib/gemstack/mail/testing.rb
45
+ - lib/gemstack-mail.rb
67
46
  homepage: https://github.com/gemstack-rb/gemstack
68
47
  licenses:
69
48
  - MIT
70
49
  metadata:
71
50
  rubygems_mfa_required: 'true'
72
- source_code_uri: https://github.com/gemstack-rb/gemstack/tree/main/gems/gemstack-mail
73
- changelog_uri: https://github.com/gemstack-rb/gemstack/blob/main/gems/gemstack-mail/CHANGELOG.md
51
+ source_code_uri: https://github.com/gemstack-rb/gemstack
52
+ changelog_uri: https://github.com/gemstack-rb/gemstack/blob/main/CHANGELOG.md
74
53
  bug_tracker_uri: https://github.com/gemstack-rb/gemstack/issues
75
54
  documentation_uri: https://github.com/gemstack-rb/gemstack/tree/main/docs
55
+ post_install_message: gemstack-mail is now part of the gemstack gem. Remove `gem "gemstack-mail"`
56
+ from your Gemfile and make sure `config/app.rb` has `require "gemstack/mail"` (apps
57
+ created with 0.3.0 do).
76
58
  rdoc_options: []
77
59
  require_paths:
78
60
  - lib
@@ -89,6 +71,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
89
71
  requirements: []
90
72
  rubygems_version: 4.0.20
91
73
  specification_version: 4
92
- summary: 'GemStack mail: mailers, templates, SMTP/log/test delivery, deliver_later
93
- via jobs'
74
+ summary: Merged into the gemstack gem — remove gemstack-mail from your Gemfile
94
75
  test_files: []
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "gemstack/jobs"
4
-
5
- module GemStack
6
- module Mail
7
- # Delivers a mailer action in the background (Delivery#deliver_later).
8
- # Retried like any job; SMTP errors are transient more often than not.
9
- class DeliveryJob < GemStack::Job
10
- def self.queue(name = nil) = name ? super : (@queue || Mail.config.queue)
11
-
12
- def perform(mailer_name, action, args)
13
- mailer = Object.const_get(mailer_name)
14
- raise ArgumentError, "#{mailer_name} is not a GemStack::Mailer" unless mailer.is_a?(Class) && mailer < Mailer
15
-
16
- Mailer::Delivery.new(mailer, action, args).deliver_now
17
- end
18
- end
19
- end
20
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "gemstack/mail"
4
-
5
- module GemStack
6
- module Mail
7
- # Test helpers (included into GemStack::TestCase by `gemstack add auth`):
8
- #
9
- # assert_emails(1) { post_json "/api/auth/password/forgot", { email: user.email } }
10
- # assert_equal [user.email], last_email.to
11
- module Testing
12
- def before_setup
13
- super
14
- Mail.deliveries.clear
15
- end
16
-
17
- def deliveries = Mail.deliveries
18
- def last_email = Mail.deliveries.last
19
-
20
- def assert_emails(count, &block)
21
- before = Mail.deliveries.size
22
- adapter = defined?(GemStack::Jobs) && GemStack::Jobs.adapter
23
- adapter = nil unless adapter.respond_to?(:perform_enqueued)
24
- queued = adapter ? adapter.enqueued.map { |job| job["id"] } : []
25
- block&.call
26
- # deliver_later mail sent inside the block counts too.
27
- adapter&.perform_enqueued(only: ["GemStack::Mail::DeliveryJob"], except_ids: queued)
28
- assert_equal count, Mail.deliveries.size - before,
29
- "Expected #{count} email(s), got #{Mail.deliveries.size - before}"
30
- end
31
- end
32
- end
33
- end
data/lib/gemstack/mail.rb DELETED
@@ -1,232 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "mail"
4
- require "erubi"
5
- require "uri"
6
- require "gemstack/core"
7
-
8
- module GemStack
9
- # Email.
10
- #
11
- # class AccountMailer < GemStack::Mailer
12
- # default from: "Shop <hello@shop.test>"
13
- #
14
- # def welcome(user_id)
15
- # @user = User.find(user_id)
16
- # mail to: @user.email, subject: "Welcome!" # templates/account_mailer/welcome.{text,html}.erb
17
- # end
18
- # end
19
- #
20
- # AccountMailer.welcome(user.id).deliver_later # through GemStack::Jobs (pass ids)
21
- # AccountMailer.welcome(user.id).deliver_now
22
- module Mail
23
- class Config < Settings
24
- # :smtp (production), :log (development: logged and saved to tmp/mail),
25
- # :test (captured in GemStack::Mail.deliveries), or an object with #deliver(message).
26
- setting :delivery, default: lambda {
27
- if GemStack.env.test? then :test
28
- elsif GemStack.env.development? then :log
29
- else :smtp
30
- end
31
- }
32
- # smtp://user:password@smtp.example.com:587 (STARTTLS) or smtps://…:465
33
- setting :smtp_url, default: -> { ENV.fetch("SMTP_URL", nil) }
34
- setting :default_from, default: -> { ENV.fetch("MAIL_FROM", "#{GemStack.config.name} <no-reply@localhost>") }
35
- setting :templates_path, default: "app/mailers/templates"
36
- setting :preview_dir, default: "tmp/mail"
37
- # Queue used by deliver_later.
38
- setting :queue, default: "mailers"
39
- end
40
-
41
- class DeliveryError < Error; end
42
-
43
- # Loaded on first use, also by a jobs worker resolving the queued class name.
44
- autoload :DeliveryJob, "gemstack/mail/delivery_job"
45
-
46
- @deliveries = []
47
- @mutex = Mutex.new
48
-
49
- class << self
50
- def config = GemStack.config.mail
51
-
52
- # Messages delivered with the :test method.
53
- attr_reader :deliveries
54
-
55
- def deliver(message)
56
- method = config.delivery
57
- case method
58
- when :test, "test" then @mutex.synchronize { @deliveries << message }
59
- when :log, "log" then deliver_to_log(message)
60
- when :smtp, "smtp" then deliver_smtp(message)
61
- else
62
- unless method.respond_to?(:deliver)
63
- raise ConfigurationError,
64
- "a mail delivery method must respond to #deliver"
65
- end
66
-
67
- method.deliver(message)
68
- end
69
- GemStack.logger.info("mail.delivered", to: Array(message.to).join(","), subject: message.subject,
70
- via: method.is_a?(Symbol) ? method : method.class.name)
71
- message
72
- end
73
-
74
- def smtp_settings(url = config.smtp_url)
75
- if url.to_s.empty?
76
- raise ConfigurationError,
77
- "set SMTP_URL (e.g. smtp://user:pass@smtp.example.com:587) to send mail"
78
- end
79
-
80
- uri = URI.parse(url)
81
- {
82
- address: uri.host, port: uri.port || (uri.scheme == "smtps" ? 465 : 587),
83
- user_name: uri.user && URI.decode_www_form_component(uri.user),
84
- password: uri.password && URI.decode_www_form_component(uri.password),
85
- authentication: uri.user ? :plain : nil, tls: uri.scheme == "smtps",
86
- enable_starttls_auto: uri.scheme != "smtps", open_timeout: 5, read_timeout: 10
87
- }.compact
88
- end
89
-
90
- private
91
-
92
- def deliver_smtp(message)
93
- message.delivery_method(:smtp, smtp_settings)
94
- message.deliver
95
- rescue Net::SMTPError, SocketError, SystemCallError, Timeout::Error, OpenSSL::SSL::SSLError => e
96
- raise DeliveryError, "SMTP delivery failed: #{e.class}: #{e.message}"
97
- end
98
-
99
- # Development: a log line plus a copy on disk (.eml, and .html to open in a browser).
100
- def deliver_to_log(message)
101
- dir = File.expand_path(config.preview_dir, GemStack.config.root)
102
- FileUtils.mkdir_p(dir)
103
- slug = message.subject.to_s.downcase.gsub(/[^a-z0-9]+/, "-").delete_prefix("-")[0, 40]
104
- base = File.join(dir, "#{Time.now.strftime("%Y%m%d-%H%M%S-%L")}-#{slug}")
105
- File.write("#{base}.eml", message.to_s)
106
- html = message.html_part&.decoded
107
- File.write("#{base}.html", html) if html
108
- GemStack.logger.info("mail saved", to: Array(message.to).join(","), subject: message.subject,
109
- file: "#{base}#{".html" if html}")
110
- end
111
- end
112
- end
113
-
114
- # Base class for mailers. Public instance methods are mail "actions";
115
- # calling one on the class returns a Delivery. An action that returns
116
- # without calling `mail` sends nothing (e.g. the user was deleted since).
117
- class Mailer
118
- # Rendered as the value of @variables set in the action.
119
- class TemplateContext
120
- def initialize(mailer)
121
- mailer.instance_variables.each { |ivar| instance_variable_set(ivar, mailer.instance_variable_get(ivar)) }
122
- end
123
-
124
- def render(source, escape:) = instance_eval(Erubi::Engine.new(source, escape: escape).src)
125
- end
126
-
127
- # A message waiting to be delivered.
128
- class Delivery
129
- attr_reader :mailer_class, :action, :args
130
-
131
- def initialize(mailer_class, action, args)
132
- @mailer_class = mailer_class
133
- @action = action
134
- @args = args
135
- end
136
-
137
- def message
138
- return @message if defined?(@message)
139
-
140
- @message = mailer_class.new.build(action, args)
141
- end
142
-
143
- # nil when the action decided not to send (it returned without calling mail).
144
- def deliver_now
145
- msg = message
146
- msg && Mail.deliver(msg)
147
- end
148
-
149
- # Delivers from a background job (arguments must be JSON values — pass ids).
150
- def deliver_later(wait: nil)
151
- require "gemstack/jobs"
152
- job = wait ? Mail::DeliveryJob.set(wait: wait) : Mail::DeliveryJob
153
- job.perform_later(mailer_class.name, action.to_s, args)
154
- rescue LoadError
155
- raise ConfigurationError, "deliver_later needs gemstack-jobs; add it to the Gemfile or use deliver_now"
156
- end
157
- end
158
-
159
- class << self
160
- def default(**headers) = defaults.merge!(headers.transform_keys(&:to_sym))
161
- def defaults = @defaults ||= superclass.respond_to?(:defaults) ? superclass.defaults.dup : {}
162
-
163
- def actions
164
- (public_instance_methods(true) - Mailer.public_instance_methods(true)).map(&:to_s)
165
- end
166
-
167
- def respond_to_missing?(name, include_private = false) = actions.include?(name.to_s) || super
168
-
169
- def method_missing(name, *args)
170
- return super unless actions.include?(name.to_s)
171
-
172
- Delivery.new(self, name.to_s, args)
173
- end
174
- end
175
-
176
- def build(action, args)
177
- @action = action
178
- public_send(action, *args)
179
- GemStack.logger.debug("mail skipped", mailer: self.class.name, action: action) unless @message
180
- @message
181
- end
182
-
183
- # Builds the message. Bodies come from text:/html: or, when omitted, from
184
- # templates: <templates_path>/<mailer>/<action>.text.erb and .html.erb
185
- # (HTML templates escape <%= %> output; use <%== %> for trusted markup).
186
- def mail(to:, subject:, text: nil, html: nil, from: nil, cc: nil, bcc: nil, reply_to: nil, template: @action)
187
- headers = self.class.defaults
188
- text ||= render_template(template, "text", escape: false)
189
- html ||= render_template(template, "html", escape: true)
190
- raise Error, "#{self.class.name}##{@action}: no body (give text:/html: or add a template)" unless text || html
191
-
192
- @message = build_message(to: to, subject: subject, text: text, html: html,
193
- from: from || headers[:from] || Mail.config.default_from, cc: cc, bcc: bcc,
194
- reply_to: reply_to || headers[:reply_to])
195
- end
196
-
197
- private
198
-
199
- def render_template(name, format, escape:)
200
- path = File.join(GemStack.config.root, Mail.config.templates_path, Inflector.underscore(self.class.name),
201
- "#{name}.#{format}.erb")
202
- return nil unless File.file?(path)
203
-
204
- TemplateContext.new(self).render(File.read(path), escape: escape)
205
- end
206
-
207
- def build_message(to:, subject:, text:, html:, from:, cc:, bcc:, reply_to:)
208
- message = ::Mail.new
209
- message.from = from
210
- message.to = to
211
- message.cc = cc if cc
212
- message.bcc = bcc if bcc
213
- message.reply_to = reply_to if reply_to
214
- message.subject = subject
215
- if text
216
- message.text_part = ::Mail::Part.new do
217
- body text
218
- content_type "text/plain; charset=UTF-8"
219
- end
220
- end
221
- if html
222
- message.html_part = ::Mail::Part.new do
223
- body html
224
- content_type "text/html; charset=UTF-8"
225
- end
226
- end
227
- message
228
- end
229
- end
230
- end
231
-
232
- GemStack::Config.namespace(:mail, GemStack::Mail::Config)