po_box 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +103 -0
- data/Rakefile +8 -0
- data/app/assets/config/po_box_manifest.js +1 -0
- data/app/assets/stylesheets/po_box/application.css +15 -0
- data/app/controllers/po_box/application_controller.rb +4 -0
- data/app/controllers/po_box/emails_controller.rb +68 -0
- data/app/controllers/po_box/inboxes_controller.rb +54 -0
- data/app/helpers/po_box/application_helper.rb +4 -0
- data/app/helpers/po_box/emails_helper.rb +4 -0
- data/app/jobs/po_box/application_job.rb +4 -0
- data/app/mailboxes/application_mailbox.rb +2 -0
- data/app/mailboxes/po_box/inbox_mailbox.rb +54 -0
- data/app/mailers/po_box/application_mailer.rb +6 -0
- data/app/mailers/po_box/emailable_mailer.rb +12 -0
- data/app/models/concerns/po_box/emailable.rb +33 -0
- data/app/models/po_box/application_record.rb +5 -0
- data/app/models/po_box/email.rb +11 -0
- data/app/models/po_box/inbox.rb +11 -0
- data/app/views/layouts/po_box/application.html.erb +12 -0
- data/app/views/layouts/po_box/mailer.html.erb +12 -0
- data/app/views/layouts/po_box/mailer.text.erb +1 -0
- data/app/views/po_box/emails/_email.html.erb +49 -0
- data/app/views/po_box/emails/_form.html.erb +51 -0
- data/app/views/po_box/emails/edit.html.erb +7 -0
- data/app/views/po_box/emails/index.html.erb +11 -0
- data/app/views/po_box/emails/new.html.erb +6 -0
- data/app/views/po_box/emails/show.html.erb +7 -0
- data/app/views/po_box/home/index.html.erb +2 -0
- data/app/views/po_box/inboxes/_form.html.erb +19 -0
- data/app/views/po_box/inboxes/_inbox.html.erb +6 -0
- data/app/views/po_box/inboxes/edit.html.erb +7 -0
- data/app/views/po_box/inboxes/index.html.erb +15 -0
- data/app/views/po_box/inboxes/new.html.erb +6 -0
- data/app/views/po_box/inboxes/show.html.erb +8 -0
- data/config/initializers/po_box.rb +1 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20230425172819_create_po_box_inboxes.rb +10 -0
- data/db/migrate/20230426005820_create_po_box_emails.rb +17 -0
- data/lib/generators/po_box/USAGE +12 -0
- data/lib/generators/po_box/po_box_generator.rb +33 -0
- data/lib/generators/po_box/templates/po_box.rb +1 -0
- data/lib/po_box/engine.rb +13 -0
- data/lib/po_box/version.rb +3 -0
- data/lib/po_box.rb +10 -0
- data/lib/tasks/po_box.rake +8 -0
- metadata +232 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4a96717f6fc9f8aee68cbf574b60c2da573d7693a1173279a84b16e1a1666d38
|
4
|
+
data.tar.gz: b5b7dcb9dcea500041f806517edc8ece9cdc18af18241900ce28adc43dd525de
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5522631b60e572e57049274c7c730d257c44eb94d0ef900b528c628329dfd0ac68e0ea166be00c8773ae3c9d3c46693c6336971881205553228760259a637b9e
|
7
|
+
data.tar.gz: d6209dc03e50daa7ff937fee1ae5b39075a4a54b7215a7e80ec9290b9502864f5e1fc341e0a3585eacdfa7d9baa7de34ee8c644032a4627c337ff649ed96fede
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2023 Leo Policastro
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
# PoBox
|
2
|
+
|
3
|
+
PoBox is a Ruby on Rails engine that provides inboxes and email addresses for your users.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
1. [ActiveStorage](https://edgeguides.rubyonrails.org/active_storage_overview.html) needs to be installed and configured.
|
8
|
+
2. [ActionMailbox](https://edgeguides.rubyonrails.org/action_mailbox_basics.html) needs to be installed and configured.
|
9
|
+
3. A model that the inbox and emails will be associated with needs to exist in the host application. e.g. `User` or `Account`.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Add this line to your application's Gemfile:
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem "po_box"
|
17
|
+
```
|
18
|
+
|
19
|
+
And then run:
|
20
|
+
|
21
|
+
```bash
|
22
|
+
$ bundle
|
23
|
+
```
|
24
|
+
|
25
|
+
Or install it yourself as:
|
26
|
+
|
27
|
+
```bash
|
28
|
+
$ gem install po_box
|
29
|
+
```
|
30
|
+
|
31
|
+
## Configuration
|
32
|
+
|
33
|
+
**IMPORTANT:** Make sure you have ActiveStorage and ActionMailbox installed and configured.
|
34
|
+
|
35
|
+
1. `bin/rails po_box:install:migrations`
|
36
|
+
2. `bin/rails g po_box emailable_model` (where `emailable_model` is the name of the model you want to make emailable, e.g. `user`)
|
37
|
+
3. `bin/rails db:migrate`
|
38
|
+
4. `bin/rails po_box:backfill_emailables`
|
39
|
+
|
40
|
+
## Limitations
|
41
|
+
|
42
|
+
1. Can only be applied to one model per application, for now.
|
43
|
+
|
44
|
+
## Usage
|
45
|
+
|
46
|
+
Visit http://localhost:3000/rails/conductor/action_mailbox/inbound_emails to send an email to your app.
|
47
|
+
|
48
|
+
Send the email to the address that is associated with the emailable model. e.g.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
User.inboxes.first.address
|
52
|
+
|
53
|
+
# => "some#64b0@yourapp"
|
54
|
+
```
|
55
|
+
|
56
|
+
<!-- If your emailable_class is a User -->
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
|
60
|
+
irb(main):003:0> u = User.last
|
61
|
+
User Load (0.4ms) SELECT "users".* FROM "users" ORDER BY "users"."id" DESC LIMIT $1 [["LIMIT", 1]]
|
62
|
+
=>
|
63
|
+
#<User:0x000000011131a328
|
64
|
+
...
|
65
|
+
irb(main):004:0> u.inboxes.first
|
66
|
+
PoBox::Inbox Load (0.4ms) SELECT "po_box_inboxes".* FROM "po_box_inboxes" WHERE "po_box_inboxes"."emailable_id" = $1 AND "po_box_inboxes"."emailable_type" = $2 ORDER BY "po_box_inboxes"."id" ASC LIMIT $3 [["emailable_id", 1], ["emailable_type", "User"], ["LIMIT", 1]]
|
67
|
+
=>
|
68
|
+
#<PoBox::Inbox:0x00000001113119a8
|
69
|
+
id: 1,
|
70
|
+
emailable_type: "User",
|
71
|
+
emailable_id: 1,
|
72
|
+
address: "some#64b0",
|
73
|
+
created_at: Thu, 04 May 2023 00:28:13.107181000 UTC +00:00,
|
74
|
+
updated_at: Thu, 04 May 2023 00:28:13.107181000 UTC +00:00>
|
75
|
+
irb(main):005:0>
|
76
|
+
|
77
|
+
irb(main):005:0> u.inboxes.first.emails.last
|
78
|
+
PoBox::Inbox Load (0.5ms) SELECT "po_box_inboxes".* FROM "po_box_inboxes" WHERE "po_box_inboxes"."emailable_id" = $1 AND "po_box_inboxes"."emailable_type" = $2 ORDER BY "po_box_inboxes"."id" ASC LIMIT $3 [["emailable_id", 1], ["emailable_type", "User"], ["LIMIT", 1]]
|
79
|
+
PoBox::Email Load (0.5ms) SELECT "po_box_emails".* FROM "po_box_emails" WHERE "po_box_emails"."inbox_id" = $1 ORDER BY "po_box_emails"."id" DESC LIMIT $2 [["inbox_id", 1], ["LIMIT", 1]]
|
80
|
+
=>
|
81
|
+
#<PoBox::Email:0x00000001079c27e8
|
82
|
+
id: 1,
|
83
|
+
inbox_id: 1,
|
84
|
+
cc: nil,
|
85
|
+
from: "anyone@aol.com",
|
86
|
+
multipart: true,
|
87
|
+
read: false,
|
88
|
+
subject: "Something subjecty",
|
89
|
+
to: "some#64b0@yourapp.com",
|
90
|
+
message_id: "6452fc3aa9815_568e39a83101b@My-MacBook-Pro-2.local.mail",
|
91
|
+
body: "Hello World",
|
92
|
+
created_at: Thu, 04 May 2023 00:28:44.171561000 UTC +00:00,
|
93
|
+
updated_at: Thu, 04 May 2023 00:28:44.483199000 UTC +00:00>
|
94
|
+
irb(main):006:0>
|
95
|
+
```
|
96
|
+
|
97
|
+
## Contributing
|
98
|
+
|
99
|
+
Bug reports and pull requests are always welcome!
|
100
|
+
|
101
|
+
## License
|
102
|
+
|
103
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//= link_directory ../stylesheets/po_box .css
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/*
|
2
|
+
* This is a manifest file that'll be compiled into application.css, which will include all the files
|
3
|
+
* listed below.
|
4
|
+
*
|
5
|
+
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
|
6
|
+
* or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
|
7
|
+
*
|
8
|
+
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
|
9
|
+
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
|
10
|
+
* files in this directory. Styles in this file should be added after the last require_* statement.
|
11
|
+
* It is generally better to create a new file per style scope.
|
12
|
+
*
|
13
|
+
*= require_tree .
|
14
|
+
*= require_self
|
15
|
+
*/
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module PoBox
|
2
|
+
class EmailsController < ApplicationController
|
3
|
+
before_action :set_inbox
|
4
|
+
before_action :set_email, only: %i[show edit update destroy]
|
5
|
+
|
6
|
+
# GET /emails
|
7
|
+
def index
|
8
|
+
@emails = Email.all
|
9
|
+
end
|
10
|
+
|
11
|
+
# GET /emails/1
|
12
|
+
def show
|
13
|
+
end
|
14
|
+
|
15
|
+
# GET /emails/new
|
16
|
+
def new
|
17
|
+
@email = Email.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# GET /emails/1/edit
|
21
|
+
def edit
|
22
|
+
end
|
23
|
+
|
24
|
+
# POST /emails
|
25
|
+
def create
|
26
|
+
@email = Email.new(email_params)
|
27
|
+
|
28
|
+
if @email.save
|
29
|
+
redirect_to inbox_email_path(@inbox, @email), notice: "Email was successfully created."
|
30
|
+
else
|
31
|
+
render :new, status: :unprocessable_entity
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# PATCH/PUT /emails/1
|
36
|
+
def update
|
37
|
+
if @email.update(email_params)
|
38
|
+
redirect_to inbox_email_path(@inbox, @email), notice: "Email was successfully updated."
|
39
|
+
else
|
40
|
+
render :edit, status: :unprocessable_entity
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# DELETE /emails/1
|
45
|
+
def destroy
|
46
|
+
@email.destroy
|
47
|
+
redirect_to inbox_emails_url(@inbox), notice: "Email was successfully destroyed."
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def set_inbox
|
53
|
+
@inbox = Inbox.find(params[:inbox_id])
|
54
|
+
rescue ActiveRecord::RecordNotFound
|
55
|
+
redirect_to po_box_inboxes_path, notice: "Inbox not found"
|
56
|
+
end
|
57
|
+
|
58
|
+
# Use callbacks to share common setup or constraints between actions.
|
59
|
+
def set_email
|
60
|
+
@email = Email.find(params[:id])
|
61
|
+
end
|
62
|
+
|
63
|
+
# Only allow a list of trusted parameters through.
|
64
|
+
def email_params
|
65
|
+
params.require(:email).permit(:inbox_id, :cc, :from, :multipart, :read, :subject, :to, :message_id)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module PoBox
|
2
|
+
class InboxesController < ApplicationController
|
3
|
+
before_action :set_inbox, only: %i[show edit update destroy]
|
4
|
+
|
5
|
+
def index
|
6
|
+
@inboxes = Inbox.all
|
7
|
+
end
|
8
|
+
|
9
|
+
def show
|
10
|
+
end
|
11
|
+
|
12
|
+
def new
|
13
|
+
@inbox = Inbox.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def edit
|
17
|
+
end
|
18
|
+
|
19
|
+
def create
|
20
|
+
@inbox = Inbox.new(inbox_params)
|
21
|
+
|
22
|
+
if @inbox.save
|
23
|
+
redirect_to @inbox, notice: "Inbox was successfully created."
|
24
|
+
else
|
25
|
+
render :new, status: :unprocessable_entity
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def update
|
30
|
+
if @inbox.update(inbox_params)
|
31
|
+
redirect_to @inbox, notice: "Inbox was successfully updated."
|
32
|
+
else
|
33
|
+
render :edit, status: :unprocessable_entity
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def destroy
|
38
|
+
@inbox.destroy
|
39
|
+
redirect_to inboxes_url, notice: "Inbox was successfully destroyed."
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def inbox_params
|
45
|
+
params.require(:inbox).permit(:name, :address)
|
46
|
+
end
|
47
|
+
|
48
|
+
def set_inbox
|
49
|
+
@inbox = Inbox.find(params[:id])
|
50
|
+
rescue ActiveRecord::RecordNotFound
|
51
|
+
redirect_to po_box_inboxes_path, notice: "Inbox not found"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module PoBox
|
2
|
+
class InboxMailbox < ApplicationMailbox
|
3
|
+
before_processing :ensure_inbox
|
4
|
+
|
5
|
+
def process
|
6
|
+
email = create_email
|
7
|
+
handle_attachments(email) if mail.attachments.any?
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def ensure_inbox
|
13
|
+
return if inbox.present?
|
14
|
+
|
15
|
+
bounce_with EmailableMailer.missing_emailable(mail)
|
16
|
+
end
|
17
|
+
|
18
|
+
def inbox
|
19
|
+
@inbox ||= PoBox::Inbox.find_by(address: address)
|
20
|
+
end
|
21
|
+
|
22
|
+
def address
|
23
|
+
mail.to.first.split("@").first
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_email
|
27
|
+
inbox.emails.create!(
|
28
|
+
cc: mail.cc,
|
29
|
+
from: mail.from.first,
|
30
|
+
multipart: mail.multipart?,
|
31
|
+
read: false,
|
32
|
+
subject: mail.subject,
|
33
|
+
to: mail.to.first,
|
34
|
+
message_id: mail.message_id,
|
35
|
+
body: if mail.html_part
|
36
|
+
mail.html_part.decoded
|
37
|
+
elsif mail.text_part
|
38
|
+
mail.text_part.decoded
|
39
|
+
else
|
40
|
+
mail.decoded
|
41
|
+
end
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
def handle_attachments(email)
|
46
|
+
mail.attachments.each do |attachment|
|
47
|
+
email.files.attach(
|
48
|
+
io: StringIO.new(attachment.body.decoded),
|
49
|
+
filename: attachment.filename
|
50
|
+
)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module PoBox
|
2
|
+
class EmailableMailer < ApplicationMailer
|
3
|
+
def missing_emailable(mail)
|
4
|
+
mail(
|
5
|
+
to: mail.sender,
|
6
|
+
subject: "Inbox not found",
|
7
|
+
body: "We were unable to find an inbox for this email. Please contact support.",
|
8
|
+
content_type: "text/html"
|
9
|
+
)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module PoBox
|
2
|
+
module Emailable
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
has_many :inboxes, as: :emailable, class_name: "PoBox::Inbox", dependent: :destroy
|
7
|
+
|
8
|
+
after_create_commit :set_inbox
|
9
|
+
|
10
|
+
accepts_nested_attributes_for :inboxes, allow_destroy: true
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def set_inbox
|
15
|
+
return if inboxes.any?
|
16
|
+
|
17
|
+
inbox_address = if email.present?
|
18
|
+
"#{email.split("@").first}##{SecureRandom.hex(2)}"
|
19
|
+
else
|
20
|
+
SecureRandom.hex(8)
|
21
|
+
end
|
22
|
+
|
23
|
+
inbox = inboxes.new
|
24
|
+
loop do
|
25
|
+
inbox.address = inbox_address
|
26
|
+
break unless PoBox.emailable_class.joins(:inboxes).where(po_box_inboxes: {address: inbox.address}).exists?
|
27
|
+
end
|
28
|
+
|
29
|
+
save
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module PoBox
|
2
|
+
class Inbox < ApplicationRecord
|
3
|
+
belongs_to :emailable, polymorphic: true, class_name: PoBox.emailable_class.to_s
|
4
|
+
|
5
|
+
has_many :emails, class_name: "PoBox::Email", dependent: :destroy
|
6
|
+
|
7
|
+
define_method PoBox.emailable_class.to_s.underscore do
|
8
|
+
emailable
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= yield %>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<div id="<%= dom_id email %>">
|
2
|
+
<% if email.cc %>
|
3
|
+
<p>
|
4
|
+
<strong>Cc:</strong>
|
5
|
+
<%= email.cc %>
|
6
|
+
</p>
|
7
|
+
<% end %>
|
8
|
+
<p>
|
9
|
+
<strong>Subject:</strong>
|
10
|
+
<%= email.subject %>
|
11
|
+
</p>
|
12
|
+
<p>
|
13
|
+
<strong>From:</strong>
|
14
|
+
<%= email.from %>
|
15
|
+
</p>
|
16
|
+
<p>
|
17
|
+
<strong>To:</strong>
|
18
|
+
<%= email.to %>
|
19
|
+
</p>
|
20
|
+
<p>
|
21
|
+
<strong>Body:</strong>
|
22
|
+
<%= email.body %>
|
23
|
+
</p>
|
24
|
+
<% email.files.each do |file| %>
|
25
|
+
<div>
|
26
|
+
<% if file.representable? %>
|
27
|
+
<%= image_tag main_app.url_for(file.representation(resize_to_limit: [100, 100])) %>
|
28
|
+
<% else %>
|
29
|
+
<%= link_to file.filename, main_app.url_for(file) %>
|
30
|
+
<% end %>
|
31
|
+
</div>
|
32
|
+
<% end %>
|
33
|
+
<p>
|
34
|
+
<strong>Multipart:</strong>
|
35
|
+
<%= email.multipart %>
|
36
|
+
</p>
|
37
|
+
<p>
|
38
|
+
<strong>Emailable ID:</strong>
|
39
|
+
<%= email.inbox_id %>
|
40
|
+
</p>
|
41
|
+
<p>
|
42
|
+
<strong>Read:</strong>
|
43
|
+
<%= email.read %>
|
44
|
+
</p>
|
45
|
+
<p>
|
46
|
+
<strong>Message ID:</strong>
|
47
|
+
<%= email.message_id %>
|
48
|
+
</p>
|
49
|
+
</div>
|
@@ -0,0 +1,51 @@
|
|
1
|
+
<%= form_with(model: email, url: url) do |form| %>
|
2
|
+
<% if email.errors.any? %>
|
3
|
+
<div style="color: red">
|
4
|
+
<h2><%= pluralize(email.errors.count, "error") %> prohibited this email from being saved:</h2>
|
5
|
+
<ul>
|
6
|
+
<% email.errors.each do |error| %>
|
7
|
+
<li><%= error.full_message %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
12
|
+
<div>
|
13
|
+
<%= form.label :inbox_id, style: "display: block" %>
|
14
|
+
<%= form.text_field :inbox_id %>
|
15
|
+
</div>
|
16
|
+
<div>
|
17
|
+
<%= form.label :cc, style: "display: block" %>
|
18
|
+
<%= form.text_field :cc %>
|
19
|
+
</div>
|
20
|
+
<div>
|
21
|
+
<%= form.label :from, style: "display: block" %>
|
22
|
+
<%= form.text_field :from %>
|
23
|
+
</div>
|
24
|
+
<div>
|
25
|
+
<%= form.label :multipart, style: "display: block" %>
|
26
|
+
<%= form.check_box :multipart %>
|
27
|
+
</div>
|
28
|
+
<div>
|
29
|
+
<%= form.label :read, style: "display: block" %>
|
30
|
+
<%= form.check_box :read %>
|
31
|
+
</div>
|
32
|
+
<div>
|
33
|
+
<%= form.label :subject, style: "display: block" %>
|
34
|
+
<%= form.text_field :subject %>
|
35
|
+
</div>
|
36
|
+
<div>
|
37
|
+
<%= form.label :to, style: "display: block" %>
|
38
|
+
<%= form.text_field :to %>
|
39
|
+
</div>
|
40
|
+
<div>
|
41
|
+
<%= form.label :message_id, style: "display: block" %>
|
42
|
+
<%= form.text_field :message_id %>
|
43
|
+
</div>
|
44
|
+
<div>
|
45
|
+
<%= form.label :body, style: "display: block" %>
|
46
|
+
<%= form.text_area :body %>
|
47
|
+
</div>
|
48
|
+
<div>
|
49
|
+
<%= form.submit %>
|
50
|
+
</div>
|
51
|
+
<% end %>
|
@@ -0,0 +1,11 @@
|
|
1
|
+
<p style="color: green"><%= notice %></p>
|
2
|
+
<h1>Emails</h1>
|
3
|
+
<div id="emails">
|
4
|
+
<% @emails.each do |email| %>
|
5
|
+
<%= render email %>
|
6
|
+
<p>
|
7
|
+
<%= link_to "Show this email", inbox_email_path(@inbox, email) %>
|
8
|
+
</p>
|
9
|
+
<% end %>
|
10
|
+
</div>
|
11
|
+
<%= link_to "New email", new_inbox_email_path(@inbox) %>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
<p style="color: green"><%= notice %></p>
|
2
|
+
<%= render @email %>
|
3
|
+
<div>
|
4
|
+
<%= link_to "Edit this email", edit_inbox_email_path(@inbox, @email) %> |
|
5
|
+
<%= link_to "Back to emails", inbox_emails_path(@inbox) %>
|
6
|
+
<%= button_to "Destroy this email", inbox_email_path(@inbox, @email, method: :delete) %>
|
7
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<%= form_with(model: inbox) do |form| %>
|
2
|
+
<% if inbox.errors.any? %>
|
3
|
+
<div style="color: red">
|
4
|
+
<h2><%= pluralize(inbox.errors.count, "error") %> prohibited this inbox from being saved:</h2>
|
5
|
+
<ul>
|
6
|
+
<% inbox.errors.each do |error| %>
|
7
|
+
<li><%= error.full_message %></li>
|
8
|
+
<% end %>
|
9
|
+
</ul>
|
10
|
+
</div>
|
11
|
+
<% end %>
|
12
|
+
<div>
|
13
|
+
<%= form.label :address, style: "display: block" %>
|
14
|
+
<%= form.text_field :address %>
|
15
|
+
</div>
|
16
|
+
<div>
|
17
|
+
<%= form.submit %>
|
18
|
+
</div>
|
19
|
+
<% end %>
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<p style="color: green"><%= notice %></p>
|
2
|
+
<h1>Email addresses</h1>
|
3
|
+
<div class="">
|
4
|
+
<%= link_to "New inbox", new_inbox_path %>
|
5
|
+
</div>
|
6
|
+
<div id="inboxes">
|
7
|
+
<% @inboxes.each do |inbox| %>
|
8
|
+
<%= render inbox %>
|
9
|
+
<div>
|
10
|
+
<%= link_to "Show this inbox", inbox %>
|
11
|
+
<%= link_to "Edit inbox", edit_inbox_path(inbox) %>
|
12
|
+
<%= button_to "Destroy", edit_inbox_path(inbox) %>
|
13
|
+
</div>
|
14
|
+
<% end %>
|
15
|
+
</div>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<p style="color: green"><%= notice %></p>
|
2
|
+
<%= render @inbox %>
|
3
|
+
<%= link_to "Emails", inbox_emails_path(@inbox) %> |
|
4
|
+
<div>
|
5
|
+
<%= link_to "Edit this inbox", edit_inbox_path() %> |
|
6
|
+
<%= link_to "Back to inboxes", inboxes_path %>
|
7
|
+
<%= button_to "Destroy this inbox", @inbox, method: :delete %>
|
8
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
PoBox.emailable_class = "Owner"
|
data/config/routes.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
class CreatePoBoxEmails < ActiveRecord::Migration[7.0]
|
2
|
+
def change
|
3
|
+
create_table :po_box_emails do |t|
|
4
|
+
t.references :inbox, foreign_key: {to_table: :po_box_inboxes}
|
5
|
+
t.string :cc
|
6
|
+
t.string :from
|
7
|
+
t.boolean :multipart
|
8
|
+
t.boolean :read, default: false, null: false
|
9
|
+
t.string :subject
|
10
|
+
t.string :to
|
11
|
+
t.string :message_id
|
12
|
+
t.text :body
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Description:
|
2
|
+
Explain the generator
|
3
|
+
|
4
|
+
Example:
|
5
|
+
bin/rails generate po_box User
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
An initializer in config/initializers/po_box.rb
|
9
|
+
A migration to add the inbox address to the emailable table
|
10
|
+
Mount the engine in config/routes.rb
|
11
|
+
Add the emailable concern to the User model
|
12
|
+
Add the route all emails to the po_box/inbox mailbox
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class PoBoxGenerator < Rails::Generators::NamedBase
|
2
|
+
source_root File.expand_path("templates", __dir__)
|
3
|
+
|
4
|
+
def setup_initializer
|
5
|
+
create_file "config/initializers/po_box.rb", "PoBox.emailable_class = \"#{name.camelize}\""
|
6
|
+
end
|
7
|
+
|
8
|
+
def mount_engine
|
9
|
+
route "mount PoBox::Engine, at: \"/po_box\""
|
10
|
+
end
|
11
|
+
|
12
|
+
def include_concerns
|
13
|
+
inject_into_file "app/models/#{name.tableize.singularize}.rb", after: "class #{name.camelize} < ApplicationRecord\n" do
|
14
|
+
<<-RUBY
|
15
|
+
include PoBox::Emailable
|
16
|
+
RUBY
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_inbox
|
21
|
+
inject_into_file "app/mailboxes/application_mailbox.rb", after: "class ApplicationMailbox < ActionMailbox::Base\n" do
|
22
|
+
<<-RUBY
|
23
|
+
routing all: "po_box/inbox"
|
24
|
+
RUBY
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def append_to_manifest
|
29
|
+
append_to_file "app/assets/config/manifest.js" do
|
30
|
+
"//= link po_box/application.css\n"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
PoBox.emailable_class = ARGV[0]
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module PoBox
|
2
|
+
mattr_accessor :application_controller
|
3
|
+
|
4
|
+
class Engine < ::Rails::Engine
|
5
|
+
isolate_namespace PoBox
|
6
|
+
|
7
|
+
config.generators do |g|
|
8
|
+
g.test_framework :rspec
|
9
|
+
g.fixture_replacement :factory_bot
|
10
|
+
g.factory_bot dir: "spec/factories"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/po_box.rb
ADDED
metadata
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: po_box
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Leo Policastro
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2023-05-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 7.0.4.3
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 7.0.4.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: factory_bot_rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: standard
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: overcommit
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: byebug
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: faker
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: shoulda-matchers
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: coderay
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: simplecov
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
description: Create inboxes for your users to send and receive emails.
|
154
|
+
email:
|
155
|
+
- lbpdev@proton.me
|
156
|
+
executables: []
|
157
|
+
extensions: []
|
158
|
+
extra_rdoc_files: []
|
159
|
+
files:
|
160
|
+
- MIT-LICENSE
|
161
|
+
- README.md
|
162
|
+
- Rakefile
|
163
|
+
- app/assets/config/po_box_manifest.js
|
164
|
+
- app/assets/stylesheets/po_box/application.css
|
165
|
+
- app/controllers/po_box/application_controller.rb
|
166
|
+
- app/controllers/po_box/emails_controller.rb
|
167
|
+
- app/controllers/po_box/inboxes_controller.rb
|
168
|
+
- app/helpers/po_box/application_helper.rb
|
169
|
+
- app/helpers/po_box/emails_helper.rb
|
170
|
+
- app/jobs/po_box/application_job.rb
|
171
|
+
- app/mailboxes/application_mailbox.rb
|
172
|
+
- app/mailboxes/po_box/inbox_mailbox.rb
|
173
|
+
- app/mailers/po_box/application_mailer.rb
|
174
|
+
- app/mailers/po_box/emailable_mailer.rb
|
175
|
+
- app/models/concerns/po_box/emailable.rb
|
176
|
+
- app/models/po_box/application_record.rb
|
177
|
+
- app/models/po_box/email.rb
|
178
|
+
- app/models/po_box/inbox.rb
|
179
|
+
- app/views/layouts/po_box/application.html.erb
|
180
|
+
- app/views/layouts/po_box/mailer.html.erb
|
181
|
+
- app/views/layouts/po_box/mailer.text.erb
|
182
|
+
- app/views/po_box/emails/_email.html.erb
|
183
|
+
- app/views/po_box/emails/_form.html.erb
|
184
|
+
- app/views/po_box/emails/edit.html.erb
|
185
|
+
- app/views/po_box/emails/index.html.erb
|
186
|
+
- app/views/po_box/emails/new.html.erb
|
187
|
+
- app/views/po_box/emails/show.html.erb
|
188
|
+
- app/views/po_box/home/index.html.erb
|
189
|
+
- app/views/po_box/inboxes/_form.html.erb
|
190
|
+
- app/views/po_box/inboxes/_inbox.html.erb
|
191
|
+
- app/views/po_box/inboxes/edit.html.erb
|
192
|
+
- app/views/po_box/inboxes/index.html.erb
|
193
|
+
- app/views/po_box/inboxes/new.html.erb
|
194
|
+
- app/views/po_box/inboxes/show.html.erb
|
195
|
+
- config/initializers/po_box.rb
|
196
|
+
- config/routes.rb
|
197
|
+
- db/migrate/20230425172819_create_po_box_inboxes.rb
|
198
|
+
- db/migrate/20230426005820_create_po_box_emails.rb
|
199
|
+
- lib/generators/po_box/USAGE
|
200
|
+
- lib/generators/po_box/po_box_generator.rb
|
201
|
+
- lib/generators/po_box/templates/po_box.rb
|
202
|
+
- lib/po_box.rb
|
203
|
+
- lib/po_box/engine.rb
|
204
|
+
- lib/po_box/version.rb
|
205
|
+
- lib/tasks/po_box.rake
|
206
|
+
homepage: https://github.com/leopolicastro/po_box
|
207
|
+
licenses:
|
208
|
+
- MIT
|
209
|
+
metadata:
|
210
|
+
homepage_uri: https://github.com/leopolicastro/po_box
|
211
|
+
source_code_uri: https://github.com/leopolicastro/po_box
|
212
|
+
changelog_uri: https://github.com/leopolicastro/po_box/blob/main/CHANGELOG.md
|
213
|
+
post_install_message:
|
214
|
+
rdoc_options: []
|
215
|
+
require_paths:
|
216
|
+
- lib
|
217
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
218
|
+
requirements:
|
219
|
+
- - ">="
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: '0'
|
222
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
223
|
+
requirements:
|
224
|
+
- - ">="
|
225
|
+
- !ruby/object:Gem::Version
|
226
|
+
version: '0'
|
227
|
+
requirements: []
|
228
|
+
rubygems_version: 3.4.10
|
229
|
+
signing_key:
|
230
|
+
specification_version: 4
|
231
|
+
summary: Create inboxes for your users to send and receive emails.
|
232
|
+
test_files: []
|