letter_opener_web 0.0.4 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -5,17 +5,9 @@ browsing sent emails.
5
5
 
6
6
  ## Installation
7
7
 
8
- Add this line to your application's Gemfile:
8
+ First add the gem to your development environment and run the `bundle` command to install it.
9
9
 
10
- gem 'letter_opener_web'
11
-
12
- And then execute:
13
-
14
- $ bundle
15
-
16
- Or install it yourself as:
17
-
18
- $ gem install letter_opener_web
10
+ gem 'letter_opener_web', :group => :development
19
11
 
20
12
  ## Usage
21
13
 
@@ -29,10 +21,31 @@ Your::Application.routes.draw do
29
21
  end
30
22
  ```
31
23
 
32
- ## Credits
24
+ If you are using [Vagrant](http://vagrantup.com), you might want to skip
25
+ `letter_opener`'s `launchy` calls and avoid messages like these:
26
+
27
+ ```terminal
28
+ 12:33:42 web.1 | Failure in opening /vagrant/tmp/letter_opener/1358825621_ba83a22/rich.html
29
+ with options {}: Unable to find a browser command. If this is unexpected, Please rerun with
30
+ environment variable LAUNCHY_DEBUG=true or the '-d' commandline option and file a bug at
31
+ https://github.com/copiousfreetime/launchy/issues/new
32
+ ```
33
+
34
+ In that case (or if you just want to browse mails using the web interface), you
35
+ can set `:letter_opener_web` as your delivery method on your
36
+ `config/environments/development.rb`:
37
+
38
+ ```ruby
39
+ config.action_mailer.delivery_method = :letter_opener_web
40
+
41
+ # If not everyone on the team is using vagrant
42
+ config.action_mailer.delivery_method = ENV['USER'] == 'vagrant' ? :letter_opener_web : :letter_opener
43
+ ```
44
+
45
+ ## Acknowledgements
33
46
 
34
- Part of the code was based on [this pull request](https://github.com/ryanb/letter_opener/pull/12)
35
- by [@alexrothenberg](https://github.com/alexrothenberg).
47
+ Special thanks to [@alexrothenberg](https://github.com/alexrothenberg) for some
48
+ ideas on [this pull request](https://github.com/ryanb/letter_opener/pull/12).
36
49
 
37
50
  ## Contributing
38
51
 
@@ -4,14 +4,38 @@
4
4
  *= require_tree .
5
5
  */
6
6
 
7
- .container-fluid {
8
- padding-top: 20px;
7
+ body {
8
+ margin: 0
9
+ }
10
+
11
+ .col {
12
+ top: 0;
13
+ bottom: 0;
14
+ }
15
+
16
+ .left {
17
+ overflow-y: auto;
18
+ width: 400px;
19
+ position: absolute;
20
+ }
21
+
22
+ .right {
23
+ left: 400px;
24
+ right: 0;
25
+ position: fixed;
9
26
  }
10
27
 
11
28
  iframe {
12
- width: 100%;
13
- min-height: 400px;
14
- border: solid 1px #ccc;
29
+ width: 100%;
30
+ height: 100%;
31
+ position: absolute;
32
+ border: solid 1px #ccc;
33
+ border-top: none;
34
+ }
35
+
36
+ h1 {
37
+ padding-right: 10px;
38
+ padding-left: 5px;
15
39
  }
16
40
 
17
41
  .letter-opener .active,
@@ -27,11 +27,11 @@ module LetterOpenerWeb
27
27
  end
28
28
 
29
29
  def plain_text
30
- @plain_text ||= read_file(:plain)
30
+ @plain_text ||= adjust_link_targets read_file(:plain)
31
31
  end
32
32
 
33
33
  def rich_text
34
- @rich_text ||= read_file(:rich)
34
+ @rich_text ||= adjust_link_targets read_file(:rich)
35
35
  end
36
36
 
37
37
  def to_param
@@ -41,21 +41,35 @@ module LetterOpenerWeb
41
41
  private
42
42
 
43
43
  def read_file(style)
44
- contents = File.read("#{letters_location}/#{id}/#{style}.html")
44
+ File.read("#{letters_location}/#{id}/#{style}.html")
45
+ end
45
46
 
47
+ def adjust_link_targets(contents)
46
48
  # We cannot feed the whole file to an XML parser as some mails are
47
49
  # "complete" (as in they have the whole <html> structure) and letter_opener
48
50
  # prepends some information about the mail being sent, making REXML
49
51
  # complain about it
50
- contents.scan(/<a[^>]+>.*?<\/a>/).each do |link|
51
- xml = REXML::Document.new(link).root
52
+ contents.scan(/<a[^>]+>(?:.|\s)*?<\/a>/).each do |link|
53
+ fixed_link = fix_link_html(link)
54
+ xml = REXML::Document.new(fixed_link).root
52
55
  unless xml.attributes['href'] =~ /(plain|rich).html/
53
56
  xml.attributes['target'] = '_blank'
54
57
  contents.gsub!(link, xml.to_s)
55
58
  end
56
59
  end
57
-
58
60
  contents
59
61
  end
62
+
63
+ def fix_link_html(link_html)
64
+ # REFACTOR: we need a better way of fixing the link inner html
65
+ link_html.dup.tap do |fixed_link|
66
+ fixed_link.gsub!('<br>', '<br/>')
67
+ fixed_link.scan(/<img(?:[^>]+?)>/).each do |img|
68
+ fixed_img = img.dup
69
+ fixed_img.gsub!(/>$/, '/>') unless img =~ /\/>$/
70
+ fixed_link.gsub!(img, fixed_img)
71
+ end
72
+ end
73
+ end
60
74
  end
61
75
  end
@@ -1,49 +1,44 @@
1
- <div class="container-fluid">
2
- <div class="row-fluid">
3
- <div class="span5">
4
- <h1>
5
- Letters
6
- <span class="pull-right">
7
- <%= link_to letters_path, class: 'btn refresh' do %>
8
- <i class="icon-refresh"></i>
9
- Refresh
10
- <% end %>
11
- <%= link_to clear_letters_path, method: 'delete', confirm: 'Are you sure?', class: 'btn btn-danger' do %>
12
- <i class="icon-trash icon-white"></i>
13
- Clear
14
- <% end %>
15
- </span>
16
- </h1>
17
- <table class="table table-hover letter-opener" data-letters-path="<%= letters_path %>">
18
- <thead>
19
- <tr>
20
- <th>ID</th>
21
- <th>Sent at</th>
22
- </tr>
23
- </thead>
24
- <tbody>
25
- <% if first_letter = @letters.shift %>
26
- <tr class="active">
27
- <td>
28
- <%= link_to(first_letter.id, letter_path(first_letter, style: 'rich'), target: 'mail') %>
29
- </td>
30
- <td><%= first_letter.sent_at %></td>
31
- </tr>
32
- <% end %>
33
- <% @letters.each do |letter| %>
34
- <tr>
35
- <td>
36
- <%= link_to(letter.id, letter_path(letter, style: 'rich'), target: 'mail') %>
37
- </td>
38
- <td><%= letter.sent_at %></td>
39
- </tr>
40
- <% end %>
41
- </tbody>
42
- </table>
43
- </div>
44
- <div class="span7">
45
- <h1>Content</h1>
46
- <iframe name="mail" id="mail" src="<%= first_letter.present? ? letter_path(first_letter, style: 'rich') : 'about:blank' %>"></iframe>
47
- </div>
48
- </div>
1
+ <div class="col left">
2
+ <h1>
3
+ Letters
4
+ <span class="pull-right">
5
+ <%= link_to letters_path, class: 'btn refresh' do %>
6
+ <i class="icon-refresh"></i>
7
+ Refresh
8
+ <% end %>
9
+ <%= link_to clear_letters_path, method: 'delete', confirm: 'Are you sure?', class: 'btn btn-danger' do %>
10
+ <i class="icon-trash icon-white"></i>
11
+ Clear
12
+ <% end %>
13
+ </span>
14
+ </h1>
15
+ <table class="table table-hover letter-opener" data-letters-path="<%= letters_path %>">
16
+ <thead>
17
+ <tr>
18
+ <th>ID</th>
19
+ <th>Sent at</th>
20
+ </tr>
21
+ </thead>
22
+ <tbody>
23
+ <% if first_letter = @letters.shift %>
24
+ <tr class="active">
25
+ <td>
26
+ <%= link_to(first_letter.id, letter_path(first_letter, style: 'rich'), target: 'mail') %>
27
+ </td>
28
+ <td><%= first_letter.sent_at %></td>
29
+ </tr>
30
+ <% end %>
31
+ <% @letters.each do |letter| %>
32
+ <tr>
33
+ <td>
34
+ <%= link_to(letter.id, letter_path(letter, style: 'rich'), target: 'mail') %>
35
+ </td>
36
+ <td><%= letter.sent_at %></td>
37
+ </tr>
38
+ <% end %>
39
+ </tbody>
40
+ </table>
41
+ </div>
42
+ <div class="col right">
43
+ <iframe name="mail" id="mail" src="<%= first_letter.present? ? letter_path(first_letter, style: 'rich') : 'about:blank' %>"></iframe>
49
44
  </div>
@@ -0,0 +1,8 @@
1
+ require 'letter_opener/delivery_method'
2
+
3
+ module LetterOpenerWeb
4
+ class DeliveryMethod < LetterOpener::DeliveryMethod
5
+ # "Replaces" original Launchy constant with a noop one
6
+ module Launchy; def open; end; end
7
+ end
8
+ end
@@ -1,7 +1,12 @@
1
1
  require 'letter_opener'
2
+ require 'letter_opener_web/delivery_method'
2
3
 
3
4
  module LetterOpenerWeb
4
5
  class Engine < ::Rails::Engine
5
6
  isolate_namespace LetterOpenerWeb
7
+
8
+ initializer "letter_opener_web.add_delivery_method" do
9
+ ActionMailer::Base.add_delivery_method :letter_opener_web, LetterOpenerWeb::DeliveryMethod, :location => Rails.root.join("tmp", "letter_opener")
10
+ end
6
11
  end
7
12
  end
@@ -1,3 +1,3 @@
1
1
  module LetterOpenerWeb
2
- VERSION = "0.0.4"
2
+ VERSION = "1.0.0.rc1"
3
3
  end
@@ -3,6 +3,18 @@ require 'spec_helper'
3
3
  describe LetterOpenerWeb::Letter do
4
4
  let(:location) { File.expand_path('../../../tmp', __FILE__) }
5
5
 
6
+ def rich_text(mail_id)
7
+ <<-MAIL
8
+ Rich text for #{mail_id}
9
+ <!DOCTYPE html>
10
+ <a href='a-link.html'>
11
+ <img src='an-image.jpg'>
12
+ Link text
13
+ </a>
14
+ <a href='fooo.html'>Bar</a>
15
+ MAIL
16
+ end
17
+
6
18
  before :each do
7
19
  described_class.stub(:letters_location).and_return(location)
8
20
  described_class.any_instance.stub(:letters_location).and_return(location)
@@ -10,7 +22,7 @@ describe LetterOpenerWeb::Letter do
10
22
  ['1111_1111', '2222_2222'].each do |folder|
11
23
  FileUtils.mkdir_p("#{location}/#{folder}")
12
24
  File.open("#{location}/#{folder}/plain.html", 'w') {|f| f.write("Plain text for #{folder}") }
13
- File.open("#{location}/#{folder}/rich.html", 'w') {|f| f.write("Rich text for #{folder} <!DOCTYPE html><a href='a-link.html'><img src='an-image.jpg'/>Link text</a><a href='fooo.html'>Bar</a>") }
25
+ File.open("#{location}/#{folder}/rich.html", 'w') {|f| f.write(rich_text(folder)) }
14
26
  FileUtils.mkdir_p("#{Rails.root.join('tmp', 'letter_opener')}/#{folder}")
15
27
  File.open("#{Rails.root.join('tmp', 'letter_opener')}/#{folder}/rich.html", 'w') {|f| f.write("Rich text for #{folder}") }
16
28
  end
@@ -27,7 +39,7 @@ describe LetterOpenerWeb::Letter do
27
39
  it { should =~ /Rich text for 1111_1111/ }
28
40
 
29
41
  it 'changes links to show up on a new window' do
30
- subject.should include("<a href='a-link.html' target='_blank'><img src='an-image.jpg'/>Link text</a>")
42
+ subject.should include("<a href='a-link.html' target='_blank'>\n <img src='an-image.jpg'/>\n Link text\n</a>")
31
43
  end
32
44
  end
33
45
 
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: letter_opener_web
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
5
- prerelease:
4
+ version: 1.0.0.rc1
5
+ prerelease: 6
6
6
  platform: ruby
7
7
  authors:
8
8
  - Fabio Rehm
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-21 00:00:00.000000000 Z
12
+ date: 2013-01-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  prerelease: false
@@ -116,6 +116,7 @@ files:
116
116
  - config/routes.rb
117
117
  - letter_opener_web.gemspec
118
118
  - lib/letter_opener_web.rb
119
+ - lib/letter_opener_web/delivery_method.rb
119
120
  - lib/letter_opener_web/engine.rb
120
121
  - lib/letter_opener_web/version.rb
121
122
  - lib/tasks/letter_opener_web_tasks.rake
@@ -132,7 +133,6 @@ files:
132
133
  - test-app/Gemfile
133
134
  - test-app/boot.rb
134
135
  - test-app/config.ru
135
- - test-app/server
136
136
  - vendor/assets/images/glyphicons-halflings-white.png
137
137
  - vendor/assets/images/glyphicons-halflings.png
138
138
  - vendor/assets/javascripts/bootstrap.min.js
@@ -151,16 +151,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
151
151
  version: '0'
152
152
  segments:
153
153
  - 0
154
- hash: -2526827428005844609
154
+ hash: 1643091472553674558
155
155
  none: false
156
156
  required_rubygems_version: !ruby/object:Gem::Requirement
157
157
  requirements:
158
- - - ! '>='
158
+ - - ! '>'
159
159
  - !ruby/object:Gem::Version
160
- version: '0'
161
- segments:
162
- - 0
163
- hash: -2526827428005844609
160
+ version: 1.3.1
164
161
  none: false
165
162
  requirements: []
166
163
  rubyforge_project:
@@ -1,17 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require './boot'
4
-
5
- options = {
6
- :environment => nil,
7
- :pid => nil,
8
- :Port => 3000,
9
- :Host => "0.0.0.0",
10
- :AccessLog => [],
11
- :app => TinyRailsApp,
12
-
13
- # TODO:
14
- # :server => 'thin'
15
- }
16
-
17
- Rack::Server.start options