postmortem 0.2.1 → 0.2.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: 1f42efab8900862f405e8f2d297dcc4b64880cfbfd354cacd829743b98d745bd
4
- data.tar.gz: bee3ff5412d6998399a3139744f80b0c97afa497c0d3e837c743d559fef6da16
3
+ metadata.gz: e0231d0fd15050a1535451df10e0a700f2218345be118d911c495285c35548c3
4
+ data.tar.gz: 5427f04480ae4b3d59fc169949429ab17e8451cff4a7b008b84c5457766fde6b
5
5
  SHA512:
6
- metadata.gz: 3e4152b134d8e9f5dcf6ef0eda380e89322135ca552b70ef8fea65970568b4116ebc1a97b709acd157fef68a0b9002d2cdb47a1f452b714da197af837beb75df
7
- data.tar.gz: fa587024f07200df9d44eb9d457d19d57a500bab0f5ecd29f310af5ee700ffda888df069c322d6dd366fe072147d975d62b10d347d1798af0d423d68d12535b9
6
+ metadata.gz: e7568bba76a5439455684d7691216eb01e3e18165693ef649d85e981ed4cb88ab9fcfbb34abcc0d801e2080dcbd6ec4b6e10534221998c227a821e01c33d0593
7
+ data.tar.gz: 7f7467751d3d4975d908e322f58c2cf1c0948c213ef6a01e28c5071db52f682fcec41c515fe21067cae95cd4d4924e1dac5682e069a5d4f734d0abb9db0707d9
data/README.md CHANGED
@@ -23,7 +23,7 @@ Add the gem to your application's Gemfile:
23
23
 
24
24
  ```ruby
25
25
  group :development, :test do
26
- gem 'postmortem', '~> 0.2.1'
26
+ gem 'postmortem', '~> 0.2.3'
27
27
  end
28
28
  ```
29
29
 
@@ -62,7 +62,8 @@
62
62
  </div>
63
63
  </div>
64
64
  </div>
65
- <iframe id="index-iframe" src="index.html"></iframe>
65
+ <iframe id="index-iframe" src="postmortem_index.html"></iframe>
66
+ <iframe id="identity-iframe" src="postmortem_identity.html"></iframe>
66
67
  <script type="text/javascript">
67
68
  <%= javascript_dependencies %>
68
69
  </script>
data/layout/layout.css CHANGED
@@ -147,7 +147,7 @@
147
147
  height: 100%;
148
148
  }
149
149
 
150
- #index-iframe {
150
+ #index-iframe, #identity-iframe {
151
151
  display: none;
152
152
  }
153
153
 
data/layout/layout.js CHANGED
@@ -1,11 +1,14 @@
1
1
  (function () {
2
2
  let previousInbox;
3
3
  let currentView;
4
+ let reloadIdentityIframeTimeout;
5
+ let identityUuid;
4
6
  let indexUuid;
5
7
  let inboxInitialized = false;
6
8
 
7
9
  var htmlIframeDocument = document.querySelector("#html-iframe").contentDocument;
8
10
  var indexIframe = document.querySelector("#index-iframe");
11
+ var identityIframe = document.querySelector("#identity-iframe");
9
12
  var textIframeDocument = document.querySelector("#text-iframe").contentDocument;
10
13
  var sourceIframeDocument = document.querySelector("#source-iframe").contentDocument;
11
14
  var sourceHighlightBundle = [
@@ -22,16 +25,21 @@
22
25
  const initialize = () => {
23
26
  loadMail(initialData);
24
27
 
25
- let reloadIframeTimeout = setTimeout(() => indexIframe.src += '', 3000);
28
+ reloadIdentityIframeTimeout = setTimeout(() => identityIframe.src += '', 3000);
26
29
 
27
30
  window.addEventListener('message', function (ev) {
28
- clearTimeout(reloadIframeTimeout);
29
- reloadIframeTimeout = setTimeout(() => indexIframe.src += '', 3000);
30
- if (indexUuid !== ev.data.uuid) renderInbox(ev.data.mails);
31
- indexUuid = ev.data.uuid;
31
+ switch (ev.data.type) {
32
+ case 'index':
33
+ renderInbox(ev.data.uuid, ev.data.mails);
34
+ break;
35
+ case 'identity':
36
+ compareIdentity(ev.data.uuid);
37
+ break;
38
+ };
32
39
  });
33
40
 
34
41
  setInterval(function () { indexIframe.contentWindow.postMessage('HELO', '*'); }, 1000);
42
+ setInterval(function () { identityIframe.contentWindow.postMessage('HELO', '*'); }, 1000);
35
43
 
36
44
  toolbar.html.onclick = function (ev) { setView('html', ev); };
37
45
  toolbar.text.onclick = function (ev) { setView('text', ev); };
@@ -215,25 +223,36 @@
215
223
  $("#download-link").attr('href', uri);
216
224
  };
217
225
 
218
- const renderInbox = function (mails) {
219
- const html = mails.map((mail, invertedIndex) => {
220
- const index = (mails.length - 1) - invertedIndex;
226
+ const compareIdentity = (uuid) => {
227
+ clearTimeout(reloadIdentityIframeTimeout);
228
+ reloadIdentityIframeTimeout = setTimeout(() => identityIframe.src += '', 3000);
229
+ if (identityUuid !== uuid) indexIframe.src += '';
230
+ identityUuid = uuid;
231
+ };
232
+
233
+ const renderInbox = (uuid, mails) => {
234
+ if (uuid === indexUuid) {
235
+ return;
236
+ }
237
+ const mailsById = {};
238
+ const html = mails.map((mail, index) => {
221
239
  const parsedTimestamp = new Date(mail.timestamp);
222
240
  const timestampSpan = `<span class="timestamp">${parsedTimestamp.toLocaleString()}</span>`;
223
241
  const classes = ['list-group-item', 'inbox-item'];
224
- if (window.location.hash === '#' + index) classes.push('active');
225
- return `<li data-email-index="${index}" class="${classes.join(' ')}"><a title="${mail.subject}" href="javascript:void(0)">${mail.subject}</a>${timestampSpan}</li>`
242
+ if (window.location.hash === '#' + mail.id) classes.push('active');
243
+ mailsById[mail.id] = mail;
244
+ return `<li data-email-id="${mail.id}" class="${classes.join(' ')}"><a title="${mail.subject}" href="javascript:void(0)">${mail.subject}</a>${timestampSpan}</li>`
226
245
  });
227
246
  if (arrayIdentical(html, previousInbox)) return;
228
247
  previousInbox = html;
229
248
  $('#inbox').html('<ul class="list-group">' + html.join('\n') + '</ul>');
230
249
  $('.inbox-item').click((ev) => {
231
250
  const $target = $(ev.currentTarget);
232
- const index = $target.data('email-index');
251
+ const id = $target.data('email-id');
233
252
  $('.inbox-item').removeClass('active');
234
253
  $target.addClass('active');
235
- window.location.hash = index;
236
- setTimeout(() => loadMail(mails[index].content), 0);
254
+ window.location.hash = id;
255
+ setTimeout(() => loadMail(mailsById[id].content), 0);
237
256
  });
238
257
 
239
258
  if (!inboxInitialized) {
@@ -242,6 +261,7 @@
242
261
  setVisible(inbox, true);
243
262
  }
244
263
  inboxInitialized = true;
264
+ indexUuid = uuid;
245
265
  };
246
266
 
247
267
  initialize();
@@ -0,0 +1,20 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <body>
4
+ <div data-uuid="<%= uuid %>" id="identity">
5
+ </div>
6
+ <script>
7
+ window.addEventListener('message', function (ev) {
8
+ const identity = document.querySelector('#identity');
9
+ const uuid = identity.dataset.uuid;
10
+ const type = 'identity';
11
+ ev.source.postMessage({ uuid, type }, '*');
12
+ });
13
+
14
+ setInterval(function () {
15
+ window.location.reload();
16
+ }, 3000);
17
+
18
+ </script>
19
+ </body>
20
+ </html>
@@ -1,7 +1,7 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
3
  <body>
4
- <div data-uuid="<%= SecureRandom.uuid %>" id="index">
4
+ <div data-uuid="<%= uuid %>" id="index">
5
5
  ### INDEX START
6
6
  <% encoded_index.each do |encoded| -%>
7
7
  <%= encoded %>
@@ -13,16 +13,13 @@
13
13
  const filter = (line) => line !== '' && !line.startsWith('### INDEX');
14
14
  const index = document.querySelector('#index');
15
15
  const uuid = index.dataset.uuid;
16
+ const type = 'index';
16
17
  const mails = index.innerText
17
18
  .split('\n')
18
19
  .filter(filter)
19
20
  .map(line => JSON.parse(atob(line)));
20
- ev.source.postMessage({ uuid, mails }, '*');
21
+ ev.source.postMessage({ uuid, type, mails }, '*');
21
22
  });
22
-
23
- setInterval(function () {
24
- window.location.reload();
25
- }, 3000);
26
23
  </script>
27
24
  </body>
28
25
  </html>
data/lib/postmortem.rb CHANGED
@@ -8,12 +8,14 @@ require 'mail'
8
8
  require 'erb'
9
9
  require 'json'
10
10
  require 'cgi'
11
+ require 'digest'
11
12
 
12
13
  require 'postmortem/version'
13
14
  require 'postmortem/adapters'
14
15
  require 'postmortem/delivery'
15
16
  require 'postmortem/layout'
16
17
  require 'postmortem/configuration'
18
+ require 'postmortem/identity'
17
19
  require 'postmortem/index'
18
20
 
19
21
  # HTML email inspection tool.
@@ -10,7 +10,7 @@ module Postmortem
10
10
  %i[from reply_to to cc bcc subject]
11
11
  .map { |field| [field, @data.public_send(field)] }
12
12
  .to_h
13
- .merge({ text_body: @data.text_part, html_body: @data.html_part })
13
+ .merge({ text_body: @data.text_part&.decoded, html_body: @data.html_part&.decoded })
14
14
  end
15
15
 
16
16
  def mail
@@ -7,8 +7,9 @@ module Postmortem
7
7
 
8
8
  def initialize(mail)
9
9
  @mail = mail
10
- @path = Postmortem.config.preview_directory.join('emails.html')
11
- @index_path = Postmortem.config.preview_directory.join('index.html')
10
+ @path = Postmortem.config.preview_directory.join('index.html')
11
+ @index_path = Postmortem.config.preview_directory.join('postmortem_index.html')
12
+ @identity_path = Postmortem.config.preview_directory.join('postmortem_identity.html')
12
13
  end
13
14
 
14
15
  def record
@@ -16,20 +17,17 @@ module Postmortem
16
17
  content = Layout.new(@mail).content
17
18
  path.write(content)
18
19
  index_path.write(index.content)
20
+ @identity_path.write(identity.content)
19
21
  end
20
22
 
21
23
  private
22
24
 
23
25
  def index
24
- @index ||= Index.new(index_path, path, timestamp, @mail)
26
+ @index ||= Index.new(index_path, path, @mail)
25
27
  end
26
28
 
27
- def timestamp
28
- @timestamp ||= Time.now
29
- end
30
-
31
- def token
32
- SecureRandom.hex(4)
29
+ def identity
30
+ @identity ||= Identity.new
33
31
  end
34
32
 
35
33
  def subject
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Postmortem
4
+ # Provides an HTML document that announces a unique ID to a parent page via JS message events.
5
+ class Identity
6
+ def content
7
+ ERB.new(File.read(path), nil, '-').result(binding)
8
+ end
9
+
10
+ private
11
+
12
+ def uuid
13
+ @uuid ||= SecureRandom.uuid
14
+ end
15
+
16
+ def path
17
+ File.expand_path(File.join(__dir__, '..', '..', 'layout', 'postmortem_identity.html.erb'))
18
+ end
19
+ end
20
+ end
@@ -3,10 +3,9 @@
3
3
  module Postmortem
4
4
  # Generates and parses an index of previously-sent emails.
5
5
  class Index
6
- def initialize(index_path, mail_path, timestamp, mail)
6
+ def initialize(index_path, mail_path, mail)
7
7
  @index_path = index_path
8
8
  @mail_path = mail_path
9
- @timestamp = timestamp.iso8601
10
9
  @mail = mail
11
10
  end
12
11
 
@@ -21,6 +20,14 @@ module Postmortem
21
20
 
22
21
  private
23
22
 
23
+ def uuid
24
+ @uuid ||= SecureRandom.uuid
25
+ end
26
+
27
+ def timestamp
28
+ Time.now.iso8601
29
+ end
30
+
24
31
  def encoded_index
25
32
  return [encoded_mail] unless @index_path.file?
26
33
 
@@ -28,13 +35,13 @@ module Postmortem
28
35
  end
29
36
 
30
37
  def encoded_mail
31
- Base64.encode64(mail_data.to_json).split("\n").join
38
+ Base64.encode64(mail_data.merge(id: Digest::MD5.hexdigest(mail_data.to_json)).to_json).split("\n").join
32
39
  end
33
40
 
34
41
  def mail_data
35
42
  {
36
43
  subject: @mail.subject || '(no subject)',
37
- timestamp: @timestamp,
44
+ timestamp: timestamp,
38
45
  path: @mail_path,
39
46
  content: @mail.serializable
40
47
  }
@@ -54,7 +61,7 @@ module Postmortem
54
61
  end
55
62
 
56
63
  def template_path
57
- File.expand_path(File.join(__dir__, '..', '..', 'layout', 'index.html.erb'))
64
+ File.expand_path(File.join(__dir__, '..', '..', 'layout', 'postmortem_index.html.erb'))
58
65
  end
59
66
  end
60
67
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Postmortem
4
- VERSION = '0.2.1'
4
+ VERSION = '0.2.3'
5
5
  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.1
4
+ version: 0.2.3
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-01-12 00:00:00.000000000 Z
11
+ date: 2021-02-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mail
@@ -145,9 +145,10 @@ files:
145
145
  - layout/dependencies.css
146
146
  - layout/dependencies.js
147
147
  - layout/headers_template.html
148
- - layout/index.html.erb
149
148
  - layout/layout.css
150
149
  - layout/layout.js
150
+ - layout/postmortem_identity.html.erb
151
+ - layout/postmortem_index.html.erb
151
152
  - lib/postmortem.rb
152
153
  - lib/postmortem/adapters.rb
153
154
  - lib/postmortem/adapters/action_mailer.rb
@@ -156,6 +157,7 @@ files:
156
157
  - lib/postmortem/adapters/pony.rb
157
158
  - lib/postmortem/configuration.rb
158
159
  - lib/postmortem/delivery.rb
160
+ - lib/postmortem/identity.rb
159
161
  - lib/postmortem/index.rb
160
162
  - lib/postmortem/layout.rb
161
163
  - lib/postmortem/plugins/action_mailer.rb