postmortem 0.2.3 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/postmortem.rb CHANGED
@@ -9,6 +9,7 @@ require 'erb'
9
9
  require 'json'
10
10
  require 'cgi'
11
11
  require 'digest'
12
+ require 'securerandom'
12
13
 
13
14
  require 'postmortem/version'
14
15
  require 'postmortem/adapters'
@@ -56,7 +57,7 @@ module Postmortem
56
57
  private
57
58
 
58
59
  def log_delivery(delivery)
59
- output_file.write(colorized(delivery.path.to_s) + "\n")
60
+ output_file.write("#{colorized(delivery.uri)}\n")
60
61
  output_file.flush
61
62
  end
62
63
 
@@ -67,7 +68,7 @@ module Postmortem
67
68
  end
68
69
 
69
70
  def output_file
70
- return STDOUT if config.log_path.nil?
71
+ return $stdout if config.log_path.nil?
71
72
 
72
73
  @output_file ||= File.open(config.log_path, mode: 'a')
73
74
  end
@@ -6,7 +6,7 @@ require 'postmortem/adapters/mail'
6
6
  require 'postmortem/adapters/pony'
7
7
 
8
8
  module Postmortem
9
- # Adapters for various email senders (e.g. ActionMailer).
9
+ # Adapters for various email senders (e.g. Mail, Pony).
10
10
  module Adapters
11
11
  end
12
12
  end
@@ -7,53 +7,18 @@ module Postmortem
7
7
  private
8
8
 
9
9
  def adapted
10
- {
11
- from: mail.from,
12
- reply_to: mail.reply_to,
13
- to: mail.to,
14
- cc: mail.cc,
15
- bcc: normalized_bcc,
16
- subject: mail.subject,
17
- text_body: text_part,
18
- html_body: html_part
19
- }
20
- end
21
-
22
- def text_part
23
- return nil unless text?
24
- return mail.body.decoded unless mail.text_part
25
-
26
- mail.text_part.decoded
27
- end
28
-
29
- def html_part
30
- return nil unless html?
31
- return mail.body.decoded unless mail.html_part
32
-
33
- mail.html_part.decoded
34
- end
35
-
36
- def mail
37
- @mail ||= ::Mail.new(@data[:mail])
10
+ %i[from reply_to to cc subject message_id]
11
+ .map { |field| [field, mail.public_send(field)] }
12
+ .to_h
13
+ .merge({ text_body: text_part, html_body: html_part, bcc: normalized_bcc })
38
14
  end
39
15
 
40
16
  def normalized_bcc
41
17
  ::Mail.new(to: @data[:bcc]).to
42
18
  end
43
19
 
44
- def text?
45
- return true unless mail.has_content_type?
46
- return true if mail.content_type.include?('text/plain')
47
- return true if mail.multipart? && mail.text_part
48
-
49
- false
50
- end
51
-
52
- def html?
53
- return true if mail.has_content_type? && mail.content_type.include?('text/html')
54
- return true if mail.multipart? && mail.html_part
55
-
56
- false
20
+ def mail
21
+ @mail ||= ::Mail.new(@data[:mail])
57
22
  end
58
23
  end
59
24
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Postmortem
4
4
  module Adapters
5
- FIELDS = %i[from reply_to to cc bcc subject text_body html_body].freeze
5
+ FIELDS = %i[from reply_to to cc bcc subject text_body html_body message_id].freeze
6
6
 
7
7
  # Base interface implementation for all Postmortem adapters.
8
8
  class Base
@@ -16,7 +16,11 @@ module Postmortem
16
16
  end
17
17
 
18
18
  def serializable
19
- FIELDS.map { |field| [camelize(field.to_s), public_send(field)] }.to_h
19
+ (%i[id] + FIELDS).map { |field| [camelize(field.to_s), public_send(field)] }.to_h
20
+ end
21
+
22
+ def id
23
+ @id ||= SecureRandom.uuid
20
24
  end
21
25
 
22
26
  FIELDS.each do |method_name|
@@ -46,6 +50,35 @@ module Postmortem
46
50
  .map { |substring, index| index.zero? ? substring : substring.capitalize }
47
51
  .join
48
52
  end
53
+
54
+ def text_part
55
+ return nil unless text?
56
+ return mail.body.decoded unless mail.text_part
57
+
58
+ mail.text_part.decoded
59
+ end
60
+
61
+ def html_part
62
+ return nil unless html?
63
+ return mail.body.decoded unless mail.html_part
64
+
65
+ mail.html_part.decoded
66
+ end
67
+
68
+ def text?
69
+ return true unless mail.has_content_type?
70
+ return true if mail.content_type.include?('text/plain')
71
+ return true if mail.multipart? && mail.text_part
72
+
73
+ false
74
+ end
75
+
76
+ def html?
77
+ return true if mail.has_content_type? && mail.content_type.include?('text/html')
78
+ return true if mail.multipart? && mail.html_part
79
+
80
+ false
81
+ end
49
82
  end
50
83
  end
51
84
  end
@@ -7,10 +7,10 @@ module Postmortem
7
7
  private
8
8
 
9
9
  def adapted
10
- %i[from reply_to to cc bcc subject]
11
- .map { |field| [field, @data.public_send(field)] }
10
+ %i[from reply_to to cc bcc subject message_id]
11
+ .map { |field| [field, mail.public_send(field)] }
12
12
  .to_h
13
- .merge({ text_body: @data.text_part&.decoded, html_body: @data.html_part&.decoded })
13
+ .merge({ text_body: text_part, html_body: html_part })
14
14
  end
15
15
 
16
16
  def mail
@@ -8,14 +8,11 @@ module Postmortem
8
8
 
9
9
  def adapted
10
10
  {
11
- from: mail.from,
12
- reply_to: mail.reply_to,
13
- to: mail.to,
14
- cc: mail.cc,
15
- bcc: mail.bcc,
11
+ from: mail.from, reply_to: mail.reply_to, to: mail.to, cc: mail.cc, bcc: mail.bcc,
16
12
  subject: mail.subject,
17
13
  text_body: @data[:body],
18
- html_body: @data[:html_body]
14
+ html_body: @data[:html_body],
15
+ message_id: mail.message_id # We use a synthetic Mail instance so this is a bit useless.
19
16
  }
20
17
  end
21
18
 
@@ -20,6 +20,10 @@ module Postmortem
20
20
  @identity_path.write(identity.content)
21
21
  end
22
22
 
23
+ def uri
24
+ "file://#{path}##{@mail.id}"
25
+ end
26
+
23
27
  private
24
28
 
25
29
  def index
@@ -35,7 +35,7 @@ module Postmortem
35
35
  end
36
36
 
37
37
  def encoded_mail
38
- Base64.encode64(mail_data.merge(id: Digest::MD5.hexdigest(mail_data.to_json)).to_json).split("\n").join
38
+ Base64.encode64(mail_data.to_json).split("\n").join
39
39
  end
40
40
 
41
41
  def mail_data
@@ -43,6 +43,7 @@ module Postmortem
43
43
  subject: @mail.subject || '(no subject)',
44
44
  timestamp: timestamp,
45
45
  path: @mail_path,
46
+ id: @mail.id,
46
47
  content: @mail.serializable
47
48
  }
48
49
  end
@@ -37,6 +37,14 @@ module Postmortem
37
37
  default_layout_directory.join('headers_template.html').read
38
38
  end
39
39
 
40
+ def favicon_b64
41
+ default_layout_directory.join('favicon.b64').read
42
+ end
43
+
44
+ def upload_url
45
+ ENV.fetch('POSTMORTEM_DELIVERY_URL', 'https://postmortem.delivery/emails')
46
+ end
47
+
40
48
  private
41
49
 
42
50
  def default_layout_directory
@@ -1,5 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  ActiveSupport::Notifications.subscribe 'deliver.action_mailer' do |*args|
4
+ delivery_method = Rails.try(:application)
5
+ &.try(:config)
6
+ &.try(:action_mailer)
7
+ &.try(:delivery_method)
8
+ next if delivery_method.nil?
9
+ next if %i[sendmail smtp].include?(delivery_method&.to_sym) # Delegate to Mail plugin.
10
+
4
11
  Postmortem.record_delivery(Postmortem::Adapters::ActionMailer.new(args.extract_options!))
5
12
  end
@@ -6,10 +6,14 @@ module Pony
6
6
  alias _original_mail mail
7
7
 
8
8
  def mail(options)
9
- # SMTP delivery is handled by Mail plugin further down the stack
10
- return _original_mail(options) if options[:via].to_s == 'smtp'
9
+ strategy = options[:via].to_s
10
+ # Pony uses the Mail gem for smtp delivery so we catch these further down the stack to
11
+ # avoid duplicating deliveries.
12
+ return _original_mail(options) if strategy == 'smtp'
11
13
 
12
- result = _original_mail(options) unless Postmortem.config.mail_skip_delivery
14
+ # When delivery method is "test" we do not want to interfere as ActionMailer.deliveries
15
+ # (which delegates to Mail::TestMailer) is typically used in tests.
16
+ result = _original_mail(options) if strategy == 'test' || !Postmortem.config.mail_skip_delivery
13
17
  Postmortem.record_delivery(Postmortem::Adapters::Pony.new(options))
14
18
  result
15
19
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Postmortem
4
- VERSION = '0.2.3'
4
+ VERSION = '0.3.1'
5
5
  end
data/postmortem.gemspec CHANGED
@@ -12,14 +12,14 @@ Gem::Specification.new do |spec|
12
12
  spec.description = 'Preview HTML emails in your browser during development'
13
13
  spec.homepage = 'https://github.com/bobf/postmortem'
14
14
  spec.license = 'MIT'
15
- spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0')
16
16
 
17
17
  spec.metadata['homepage_uri'] = spec.homepage
18
18
  spec.metadata['source_code_uri'] = spec.homepage
19
19
  spec.metadata['changelog_uri'] = 'https://github.com/bobf/postmortem/blob/master/README.md'
20
20
 
21
21
  spec.files = Dir.chdir(File.expand_path(__dir__)) do
22
- `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features|doc)/}) }
23
23
  end
24
24
  spec.bindir = 'bin'
25
25
  spec.executables = []
@@ -28,10 +28,13 @@ Gem::Specification.new do |spec|
28
28
  spec.add_runtime_dependency 'mail', '~> 2.7'
29
29
 
30
30
  spec.add_development_dependency 'actionmailer', '~> 6.0'
31
+ spec.add_development_dependency 'devpack', '~> 0.3.2'
32
+ spec.add_development_dependency 'faker', '~> 2.17'
31
33
  spec.add_development_dependency 'pony', '~> 1.13'
32
34
  spec.add_development_dependency 'rspec', '~> 3.9'
33
35
  spec.add_development_dependency 'rspec-its', '~> 1.3'
34
- spec.add_development_dependency 'rubocop', '~> 0.88.0'
36
+ spec.add_development_dependency 'rubocop', '~> 1.10'
37
+ spec.add_development_dependency 'rubocop-rspec', '~> 2.2'
35
38
  spec.add_development_dependency 'strong_versions', '~> 0.4.5'
36
39
  spec.add_development_dependency 'timecop', '~> 0.9.1'
37
40
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postmortem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bob Farrell
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-02-24 00:00:00.000000000 Z
11
+ date: 2021-04-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '6.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: devpack
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.2
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.3.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: faker
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '2.17'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '2.17'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: pony
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,14 +114,28 @@ dependencies:
86
114
  requirements:
87
115
  - - "~>"
88
116
  - !ruby/object:Gem::Version
89
- version: 0.88.0
117
+ version: '1.10'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.10'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop-rspec
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.2'
90
132
  type: :development
91
133
  prerelease: false
92
134
  version_requirements: !ruby/object:Gem::Requirement
93
135
  requirements:
94
136
  - - "~>"
95
137
  - !ruby/object:Gem::Version
96
- version: 0.88.0
138
+ version: '2.2'
97
139
  - !ruby/object:Gem::Dependency
98
140
  name: strong_versions
99
141
  requirement: !ruby/object:Gem::Requirement
@@ -140,10 +182,10 @@ files:
140
182
  - Rakefile
141
183
  - bin/console
142
184
  - bin/setup
143
- - doc/screenshot.png
144
185
  - layout/default.html.erb
145
186
  - layout/dependencies.css
146
187
  - layout/dependencies.js
188
+ - layout/favicon.b64
147
189
  - layout/headers_template.html
148
190
  - layout/layout.css
149
191
  - layout/layout.js
@@ -180,7 +222,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
180
222
  requirements:
181
223
  - - ">="
182
224
  - !ruby/object:Gem::Version
183
- version: 2.3.0
225
+ version: 2.5.0
184
226
  required_rubygems_version: !ruby/object:Gem::Requirement
185
227
  requirements:
186
228
  - - ">="
@@ -188,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
230
  version: '0'
189
231
  requirements: []
190
232
  rubyforge_project:
191
- rubygems_version: 2.7.6
233
+ rubygems_version: 2.7.6.2
192
234
  signing_key:
193
235
  specification_version: 4
194
236
  summary: Development HTML Email Inspection Tool
data/doc/screenshot.png DELETED
Binary file