gravity_mailbox 0.4.0 → 0.5.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: ce37494fe075c4031d525e51672a2a1be1f8fb283aaae7d1de7d30a5baa2ff31
4
- data.tar.gz: 360aeebf86d71e2887fdd239639be1710968d3f253b1f19e867584499bdf9c2c
3
+ metadata.gz: 05ca76cb5ec553a7fab1a1f6044e62b6cf92b3d4931070ee0eb1cae0433c30ae
4
+ data.tar.gz: 38fea7ec0c03bd1d636ef225aa12c07d82add8ef0bd0363d01b2da7c61610f3e
5
5
  SHA512:
6
- metadata.gz: 5363f0b77e08f72fbfe7153671a99f655ed7711c7d65055727ce2034a9657ae6cf5884023df7b47a2aea6ab2997e93bac746d8aa839720881180dabbbbc2b453
7
- data.tar.gz: 729affd85417e0f371980d0a39067f6039c8ac495fe6f4d126be8cd243d1d2e36aca3a71b6384d86c737ec035f989a9837ef28383a75951451fe43fbe0e76339
6
+ metadata.gz: 0c5b898f10227310153fc2497d8769151e0f594c20021232f74c0cd4e2a28079c14b144f5a23bda0f2e47a9790527e271bf9b777fce49e5f516f75bf6def370c
7
+ data.tar.gz: 2226fea11314408cfa923456ef2a9aef0a1f29370baa4c182f98430f4a12426e495b8ab18bc446cd58a84ac4effa642b0ad5e46ef12e4e8a714258e883f6f0bb
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'action_controller'
4
+
5
+ module GravityMailbox
6
+ class MailboxController < ActionController::Base
7
+ layout 'gravity_mailbox'
8
+
9
+ before_action :set_mails, only: %i[index]
10
+
11
+ def index
12
+ @part = find_preferred_part(*[request.format, Mime[:html], Mime[:text]].uniq) if @mail
13
+ return unless params[:part]
14
+
15
+ response.content_type = 'text/html'
16
+ render plain: @part&.decoded
17
+ end
18
+
19
+ def download_eml
20
+ @mail = RailsCacheDeliveryMethod.mail(params[:id])
21
+ send_data @mail.to_s, filename: "#{@mail.subject}.eml"
22
+ end
23
+
24
+ def delete
25
+ RailsCacheDeliveryMethod.delete(params[:id])
26
+ redirect_to '/gravity_mailbox'
27
+ end
28
+
29
+ def delete_all
30
+ RailsCacheDeliveryMethod.delete_all
31
+ redirect_to '/gravity_mailbox'
32
+ end
33
+
34
+ private
35
+
36
+ def find_preferred_part(*formats)
37
+ if @mail.multipart?
38
+ formats.each do |format|
39
+ part = @mail.find_first_mime_type(format)
40
+ return part if part
41
+ end
42
+ elsif formats.include?(@mail.mime_type)
43
+ @mail.body
44
+ end
45
+ end
46
+
47
+ def set_mails
48
+ @mails = RailsCacheDeliveryMethod.mails
49
+ @mail = @mails.detect { |m| m.message_id == params[:id] } if params[:id]
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,51 @@
1
+
2
+ <div class="mail-list-item <%= mail.message_id == params[:id] ? 'selected-mail' : '' %>" data-mail-id="<%= mail.message_id %>">
3
+ <div class="level" style="margin-bottom: 12px">
4
+ <div class="level-left" style="width: 80%">
5
+ <span class="has-text-weight-semibold mail-subject"><%= mail.subject %></span>
6
+ </div>
7
+ <div class="level-right">
8
+ <div class="dropdown is-right">
9
+ <div class="dropdown-trigger" style="width: 24px; height: 24px;">
10
+ <span class="icon">
11
+ <ion-icon name="ellipsis-vertical-outline"></ion-icon>
12
+ </span>
13
+ </div>
14
+ <div class="dropdown-menu" id="dropdown-menu" role="menu">
15
+ <div class="dropdown-content">
16
+ <div class="dropdown-item">
17
+ <%= link_to "/gravity_mailbox/download_eml?id=#{mail.message_id}", class: ['link-button'] do %>
18
+ <span class="icon-text">
19
+ <span class="icon has-text-centered">
20
+ <ion-icon name="download-outline"></ion-icon>
21
+ </span>
22
+ <span>Download .eml</span>
23
+ </span>
24
+ <% end %>
25
+ </div>
26
+
27
+ <div class="dropdown-item">
28
+ <%= button_to "/gravity_mailbox/delete?id=#{mail.message_id}", class: ['link-button'], method: :post do %>
29
+ <span class="icon-text">
30
+ <span class="icon has-text-centered">
31
+ <ion-icon name="trash-outline"></ion-icon>
32
+ </span>
33
+ <span>Delete</span>
34
+ </span>
35
+ <% end %>
36
+ </div>
37
+ </div>
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+
43
+ <% mail.to.each do |email_to| %>
44
+ <%= content_tag(:p, email_to, class: ['has-text-weight-light'], style: "font-size: 0.85rem") %>
45
+ <% end %>
46
+ <div class="has-text-right">
47
+ <span class="is-size-7" title="<%= I18n.l(mail.date, format: :long) %>">
48
+ <%= time_ago_in_words(mail.date) %>
49
+ </span>
50
+ </div>
51
+ </div>
@@ -0,0 +1,173 @@
1
+ <% content_for :style do %>
2
+ body, iframe {
3
+ height: 100vh;
4
+ }
5
+
6
+ iframe {
7
+ border: 0;
8
+ width: 100%;
9
+ }
10
+
11
+ .navbar {
12
+ background-color: #007bff !important;
13
+ }
14
+
15
+ .navbar-brand > h1 {
16
+ font-family: 'Righteous', cursive !important;
17
+ }
18
+
19
+ .mail-list-column {
20
+ height: 100vh;
21
+ overflow: scroll;
22
+ min-width: 20em;
23
+ }
24
+
25
+ .link-button {
26
+ background: none!important;
27
+ border: none;
28
+ padding: 0!important;
29
+ font-family: arial, sans-serif;
30
+ color: #000;
31
+ cursor: pointer;
32
+ width: 100%;
33
+ text-align: left;
34
+ }
35
+
36
+ .mail-list-item {
37
+ background-color: #fff!important;
38
+ padding: 1rem;
39
+ box-shadow: inset 0 -1px 0 0 rgb(100 121 143 / 12%) !important;
40
+ }
41
+
42
+ .mail-list-item.selected-mail {
43
+ background-color: #ffffff!important;
44
+ border-left: 8px solid #ed900c;
45
+ padding-left: calc(1rem - 8px);
46
+ }
47
+
48
+ .mail-list-item:hover {
49
+ cursor: pointer !important;
50
+ border-left: 8px solid lightgrey;
51
+ padding-left: calc(1rem - 8px);
52
+ }
53
+
54
+ .mail-list-item.selected-mail:hover {
55
+ border-left: 8px solid #ed900c;
56
+ }
57
+
58
+ #iframe-mail-container {
59
+ background-color: whitesmoke !important;
60
+ }
61
+
62
+ .dropdown-trigger:hover {
63
+ cursor: pointer !important;
64
+ }
65
+
66
+ .dropdown-item:hover {
67
+ background-color: whitesmoke !important;
68
+ }
69
+ <% end %>
70
+
71
+ <div class="columns mb-0 mt-0">
72
+ <div class="column is-one-quarter pt-0 pr-0 mail-list-column">
73
+ <div class="navbar has-background-info">
74
+ <div class="navbar-brand">
75
+ <h1 class="navbar-item title is-6 has-text-white">GravityMailbox</h1>
76
+ </div>
77
+ <div class="navbar-menu">
78
+ <div class="navbar-end">
79
+ <div class="navbar-item">
80
+ <div class="dropdown is-right" id="toolbar-dropdown">
81
+ <div class="dropdown-trigger" style="width: 24px; height: 24px;">
82
+ <span class="icon has-text-white has-text-centered" aria-controls="dropdown-menu">
83
+ <ion-icon size="large" name="menu-outline"></ion-icon>
84
+ </span>
85
+ </div>
86
+ <div class="dropdown-menu" id="dropdown-menu" role="menu">
87
+ <div class="dropdown-content">
88
+ <div class="dropdown-item">
89
+ <%= button_to '/gravity_mailbox/delete_all', class: ['link-button'], method: :post do %>
90
+ <span class="icon-text">
91
+ <span class="icon has-text-centered">
92
+ <ion-icon name="trash-outline"></ion-icon>
93
+ </span>
94
+ <span>Delete all</span>
95
+ </span>
96
+ <% end %>
97
+ </div>
98
+ </div>
99
+ </div>
100
+ </div>
101
+ </div>
102
+ </div>
103
+ </div>
104
+ </div>
105
+
106
+ <% @mails.each_with_index do |mail, index| %>
107
+ <%= render partial: 'mail', locals: { mail: mail, index: index } %>
108
+ <% end %>
109
+ </div>
110
+ <div class="column pb-0 pt-0 pl-0">
111
+ <iframe id="iframe-mail-container" seamless name="messageBody" src="<%= params[:id] ? "?part=true&id=#{params[:id]}" : '' %>"></iframe>
112
+ </div>
113
+ </div>
114
+
115
+ <script>
116
+ function closeAllOtherDropdown(e) {
117
+ document.querySelectorAll(".dropdown").forEach((dropdown) => {
118
+ dropdown.classList.remove('is-active');
119
+ })
120
+ }
121
+
122
+ // Click on mail and change iframe src
123
+ let mailItems = document.querySelectorAll(".mail-list-item")
124
+ mailItems.forEach(mailItem => {
125
+ mailItem.addEventListener("click", () => {
126
+ document.querySelector("#iframe-mail-container").src = "/gravity_mailbox?part=true&id=" + mailItem.dataset.mailId
127
+ mailItems.forEach(mailItem => mailItem.classList.remove("selected-mail"))
128
+ mailItem.classList.add("selected-mail")
129
+ })
130
+ })
131
+
132
+ // Close all dropdowns if the user clicks outside of them
133
+ document.addEventListener("click", (e) => {
134
+ document.querySelectorAll(".dropdown").forEach((dropdown) => {
135
+ dropdown.classList.remove("is-active")
136
+ })
137
+ });
138
+
139
+ // Each mail menu dropdown
140
+ document.querySelectorAll('.dropdown-trigger').forEach((dropdown) => {
141
+ dropdown.addEventListener('click', function (e) {
142
+ closeAllOtherDropdown(e)
143
+ e.target.closest(".dropdown").classList.toggle('is-active');
144
+ e.stopPropagation();
145
+ })
146
+ })
147
+
148
+ function displayAutomaticallyTheFirstEmail() {
149
+ const mailItems = document.querySelectorAll(".mail-list-item");
150
+ if (mailItems.length) {
151
+ const mailItem = mailItems[0];
152
+ document.querySelector("#iframe-mail-container").src = "/gravity_mailbox?part=true&id=" + mailItem.dataset.mailId;
153
+ mailItem.classList.add("selected-mail");
154
+ } else {
155
+ const iframe = document.querySelector("#iframe-mail-container");
156
+
157
+ const iframeBody = iframe.contentDocument.body;
158
+ if (iframeBody) {
159
+ const p = document.createElement('p');
160
+ p.textContent = "No email received yet.";
161
+ p.style.fontFamily = "sans-serif";
162
+ p.style.fontSize = "20px";
163
+ p.style.fontWeight = "100";
164
+ iframeBody.appendChild(p);
165
+ iframeBody.style.display = "flex";
166
+ iframeBody.style.justifyContent = "center";
167
+ iframeBody.style.alignItems = "center";
168
+ }
169
+ }
170
+ }
171
+
172
+ document.addEventListener("DOMContentLoaded", displayAutomaticallyTheFirstEmail);
173
+ </script>
@@ -0,0 +1,18 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta name="viewport" content="width=device-width"/>
5
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.4/css/bulma.min.css">
6
+ <link rel="preconnect" href="https://fonts.googleapis.com">
7
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
8
+ <link href="https://fonts.googleapis.com/css2?family=Righteous&display=swap" rel="stylesheet">
9
+ <style>
10
+ <%= yield :style %>
11
+ </style>
12
+ </head>
13
+ <body>
14
+ <%= yield %>
15
+ <script type="module" src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
16
+ <script nomodule src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
17
+ </body>
18
+ </html>
data/config/routes.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ GravityMailbox::Engine.routes.draw do
4
+ get '/' => 'mailbox#index', as: :index
5
+ get 'download_eml' => 'mailbox#download_eml'
6
+ post 'delete' => 'mailbox#delete'
7
+ post 'delete_all' => 'mailbox#delete_all'
8
+ end
@@ -14,6 +14,10 @@ module GravityMailbox
14
14
  end
15
15
 
16
16
  def deliver!(mail)
17
+ # https://github.com/mikel/mail/blob/d1d65b370b109b98e673a934e8b70a0c1f58cc59/lib/mail/network/delivery_methods/test_mailer.rb#L39
18
+ # Create the envelope to validate it
19
+ Mail::SmtpEnvelope.new(mail)
20
+
17
21
  key = "#{KEY_PREFIX}#{mail.message_id}"
18
22
  Rails.cache.write(key, mail.encoded, expires_in: 1.week) # TODO: setting for expiration
19
23
  actual_list = self.class.mail_keys
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GravityMailbox
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
metadata CHANGED
@@ -1,29 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gravity_mailbox
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jean-Francis Bastien
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-06-16 00:00:00.000000000 Z
11
+ date: 2025-08-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: rails
14
+ name: actionmailer
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: '6.0'
19
+ version: '7.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: '6.0'
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: railties
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '7.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '7.0'
27
41
  description: Development tools that aim to make it simple to visualize mail sent by
28
42
  your Rails app directly through your Rails app.
29
43
  email:
@@ -36,6 +50,11 @@ extra_rdoc_files:
36
50
  files:
37
51
  - LICENSE.txt
38
52
  - README.md
53
+ - app/controllers/gravity_mailbox/mailbox_controller.rb
54
+ - app/views/gravity_mailbox/mailbox/_mail.html.erb
55
+ - app/views/gravity_mailbox/mailbox/index.html.erb
56
+ - app/views/layouts/gravity_mailbox.html.erb
57
+ - config/routes.rb
39
58
  - lib/gravity_mailbox.rb
40
59
  - lib/gravity_mailbox/engine.rb
41
60
  - lib/gravity_mailbox/rails_cache_delivery_method.rb
@@ -49,7 +68,7 @@ metadata:
49
68
  source_code_uri: https://github.com/petalmd/gravity_mailbox
50
69
  bug_tracker_uri: https://github.com/petalmd/gravity_mailbox/issues
51
70
  rubygems_mfa_required: 'true'
52
- post_install_message:
71
+ post_install_message:
53
72
  rdoc_options: []
54
73
  require_paths:
55
74
  - lib
@@ -57,15 +76,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
57
76
  requirements:
58
77
  - - ">="
59
78
  - !ruby/object:Gem::Version
60
- version: 2.6.0
79
+ version: 2.7.0
61
80
  required_rubygems_version: !ruby/object:Gem::Requirement
62
81
  requirements:
63
82
  - - ">="
64
83
  - !ruby/object:Gem::Version
65
84
  version: '0'
66
85
  requirements: []
67
- rubygems_version: 3.2.3
68
- signing_key:
86
+ rubygems_version: 3.5.22
87
+ signing_key:
69
88
  specification_version: 4
70
89
  summary: Visualize mail sent by your Rails app directly through your Rails app.
71
90
  test_files: []