bookbindery 7.2.0 → 7.3.0

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
  SHA1:
3
- metadata.gz: 60647d1c7441e4f13ec25b2f905afa5b108d4428
4
- data.tar.gz: 2187d4e8f5e6accd3fbb607950a053ae6e1c5308
3
+ metadata.gz: 88ea31dee49567678221b2f7ec08271dbee24d4d
4
+ data.tar.gz: dc7bc2856531c909147a8c215466e4ca78f29224
5
5
  SHA512:
6
- metadata.gz: b625693db01e696430423e1e4889e485c1c3b84746debb95d1ea6f5b4f3464db395a40d72876c961cc75918af4c2ed1ef848e92e708b9c91020b5cf8d7b96091
7
- data.tar.gz: a497afbb4c57e31242c4cb638a761b0f0f1f9c26a2b98e96750484a9c96b97fb4b64fa398a3b21c0a1961d1800b231f3a50ca9ea82fb87bddc9e8ba399f0b01d
6
+ metadata.gz: 7edb2efc47d478fa5908c40ad733bcfd1ab73b56af875dcbbc00c49768c6356f544b1c4ff5e378e3c9ff8623a598d8628c3e53d81d8ead55a023a0e42791054c
7
+ data.tar.gz: 5899419c8b5cd1ab847ba3dd9d556f2dbc68a4fc832deb1536b306fae063fe6bfe28705dccb894c5175d342c85bb4593025e54f0ce45eb4edebcd63ef691ea42
data/bookbinder.gemspec CHANGED
@@ -2,7 +2,7 @@ require 'base64'
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = 'bookbindery'
5
- s.version = '7.2.0'
5
+ s.version = '7.3.0'
6
6
  s.summary = 'Markdown to Rackup application documentation generator'
7
7
  s.description = 'A command line utility to be run in Book repositories to stitch together their constituent Markdown repos into a static-HTML-serving application'
8
8
  s.authors = ['Mike Grafton', 'Lucas Marks', 'Gavin Morgan', 'Nikhil Gajwani', 'Dan Wendorf', 'Brenda Chan', 'Matthew Boedicker', 'Frank Kotsianas', 'Elena Sharma', 'Christa Hartsock']
@@ -23,13 +23,13 @@ Gem::Specification.new do |s|
23
23
  s.add_runtime_dependency 'middleman-syntax', ['~> 2.0']
24
24
  s.add_runtime_dependency 'rouge', '!= 1.9.1'
25
25
  s.add_runtime_dependency 'redcarpet', ['~> 3.2.3']
26
- s.add_runtime_dependency 'vienna', ['= 0.4.1']
27
26
  s.add_runtime_dependency 'anemone'
28
27
  s.add_runtime_dependency 'css_parser'
29
28
  s.add_runtime_dependency 'puma'
30
29
  s.add_runtime_dependency 'rack-rewrite'
31
30
  s.add_runtime_dependency 'therubyracer'
32
31
  s.add_runtime_dependency 'git', '~> 1.2.8'
32
+ s.add_runtime_dependency 'sendgrid-ruby'
33
33
 
34
34
  s.add_development_dependency 'license_finder'
35
35
  s.add_development_dependency 'pry-byebug'
@@ -55,7 +55,8 @@ module Bookbinder
55
55
  bind_config,
56
56
  File.expand_path('../../../../', __FILE__),
57
57
  output_locations,
58
- cloner
58
+ cloner,
59
+ ref_override: bind_options.ref_override
59
60
  )
60
61
  sections = section_repository.fetch(
61
62
  configured_sections: bind_config.sections,
@@ -8,14 +8,14 @@ module Bookbinder
8
8
  @fs = fs
9
9
  end
10
10
 
11
- def prepare_directories(config, gem_root, output_locations, cloner)
11
+ def prepare_directories(config, gem_root, output_locations, cloner, ref_override: nil)
12
12
  fs.remove_directory(output_locations.output_dir)
13
13
  fs.empty_directory(output_locations.final_app_dir)
14
14
 
15
15
  copy_directory_from_gem(gem_root, 'template_app', output_locations.final_app_dir)
16
16
  copy_directory_from_gem(gem_root, 'master_middleman', output_locations.site_generator_home)
17
17
 
18
- LayoutPreparer.new(fs).prepare(output_locations, cloner, config)
18
+ LayoutPreparer.new(fs).prepare(output_locations, cloner, ref_override, config)
19
19
  end
20
20
 
21
21
  private
@@ -8,9 +8,11 @@ module Bookbinder
8
8
 
9
9
  attr_reader :fs
10
10
 
11
- def prepare(output_locations, cloner, config)
11
+ def prepare(output_locations, cloner, ref_override, config)
12
12
  if config.has_option?('layout_repo')
13
+
13
14
  cloned_repo = cloner.call(source_repo_name: config.layout_repo,
15
+ source_ref: ref_override || config.layout_repo_ref,
14
16
  destination_parent_dir: Dir.mktmpdir)
15
17
 
16
18
  fs.copy_contents(cloned_repo.path, output_locations.site_generator_home)
@@ -71,6 +71,7 @@ module Bookbinder
71
71
  push_local_to_staging,
72
72
  Commands::PushToProd.new(streams, logger, configuration_fetcher, Dir.mktmpdir),
73
73
  Commands::RunPublishCI.new(bind, push_local_to_staging, build_and_push_tarball),
74
+ Commands::Punch.new(streams, configuration_fetcher, version_control_system),
74
75
  Commands::UpdateLocalDocRepos.new(
75
76
  streams,
76
77
  configuration_fetcher,
@@ -1,3 +1,5 @@
1
+ require 'bundler'
2
+
1
3
  module Bookbinder
2
4
  module Commands
3
5
  class Generate
@@ -0,0 +1,44 @@
1
+ require_relative '../errors/cli_error'
2
+ require_relative 'naming'
3
+
4
+ module Bookbinder
5
+ module Commands
6
+ class Punch
7
+ include Commands::Naming
8
+
9
+ def initialize(streams, configuration_fetcher, version_control_system)
10
+ @streams = streams
11
+ @configuration_fetcher = configuration_fetcher
12
+ @version_control_system = version_control_system
13
+ end
14
+
15
+ def usage
16
+ ["punch <git tag>", "Apply the specified <git tag> to your book, sections, and layout repo"]
17
+ end
18
+
19
+ def run((tag, *))
20
+ raise CliError::InvalidArguments unless tag
21
+
22
+ urls(config).each do |url|
23
+ version_control_system.remote_tag(url, tag, 'HEAD')
24
+ end
25
+
26
+ streams[:success].puts 'Success!'
27
+ streams[:out].puts "#{config.book_repo} and its sections were tagged with #{tag}"
28
+ 0
29
+ end
30
+
31
+ private
32
+
33
+ attr_reader :streams, :configuration_fetcher, :version_control_system
34
+
35
+ def urls(config)
36
+ [config.book_repo_url, config.layout_repo_url] + config.sections.map(&:repo_url).uniq
37
+ end
38
+
39
+ def config
40
+ @config ||= configuration_fetcher.fetch_config
41
+ end
42
+ end
43
+ end
44
+ end
@@ -8,6 +8,7 @@ module Bookbinder
8
8
  include Commands::Naming
9
9
 
10
10
  CredentialKeyError = Class.new(RuntimeError)
11
+ FeedbackConfigError = Class.new(RuntimeError)
11
12
  REQUIRED_AWS_KEYS = %w(access_key secret_key green_builds_bucket)
12
13
  REQUIRED_CF_KEYS = %w(username password api_endpoint organization app_name)
13
14
 
@@ -61,7 +62,7 @@ module Bookbinder
61
62
  "push_local_to_#{environment}"
62
63
  end
63
64
 
64
- def error_message
65
+ def creds_error_message
65
66
  <<-ERROR
66
67
  Cannot locate a specific key in credentials.yml.
67
68
  Your credentials file should follow this format:
@@ -88,6 +89,19 @@ cloud_foundry:
88
89
  ERROR
89
90
  end
90
91
 
92
+ def mail_error_message
93
+ <<-ERROR
94
+ Your environment variables for sending feedback are not set.
95
+
96
+ To enable feedback, you must set the following variables in your environment:
97
+
98
+ export SENDGRID_USERNAME=<your-username>
99
+ export SENDGRID_API_KEY=<your-api-key>
100
+ export FEEDBACK_TO=<email-to-receive-feedback>
101
+ export FEEDBACK_FROM=<email-to-send-feedback>
102
+ ERROR
103
+ end
104
+
91
105
  def validate
92
106
  missing_keys = []
93
107
 
@@ -106,7 +120,12 @@ cloud_foundry:
106
120
  missing_keys << key unless cf_creds.send(key)
107
121
  end
108
122
 
109
- raise CredentialKeyError.new error_message if missing_keys.any?
123
+ raise CredentialKeyError.new(creds_error_message) if missing_keys.any?
124
+ raise FeedbackConfigError.new(mail_error_message) if config.feedback_enabled && mail_vars_absent?
125
+ end
126
+
127
+ def mail_vars_absent?
128
+ !(ENV['SENDGRID_USERNAME'] && ENV['SENDGRID_API_KEY'] && ENV['FEEDBACK_TO'] && ENV['FEEDBACK_FROM'])
110
129
  end
111
130
  end
112
131
  end
@@ -24,7 +24,7 @@ module Bookbinder
24
24
 
25
25
  def section_config(sections)
26
26
  sections.reduce({}) {|config, section|
27
- config_path = section.path_to_repository.join(config_filename)
27
+ config_path = section.path_to_repo_dir.join(config_filename)
28
28
  archive_config = loader.load_key(config_path, 'archive_menu')
29
29
  if archive_config
30
30
  config.merge(section.desired_directory_name => archive_config)
@@ -66,7 +66,7 @@ module Bookbinder
66
66
  end
67
67
 
68
68
  CONFIG_REQUIRED_KEYS = %w(book_repo public_host)
69
- CONFIG_OPTIONAL_KEYS = %w(archive_menu book_repo_url cred_repo cred_repo_url layout_repo layout_repo_url sections subnav_exclusions)
69
+ CONFIG_OPTIONAL_KEYS = %w(archive_menu book_repo_url cred_repo cred_repo_url layout_repo layout_repo_ref layout_repo_url sections subnav_exclusions feedback_enabled)
70
70
 
71
71
  CONFIG_REQUIRED_KEYS.each do |method_name|
72
72
  define_method(method_name) do
@@ -31,6 +31,10 @@ module Bookbinder
31
31
  repo['ref'] || 'master'
32
32
  end
33
33
 
34
+ def at_repo_path
35
+ repo['at_path']
36
+ end
37
+
34
38
  def dependent_sections
35
39
  @sections ||= (config['dependent_sections'] || []).map do |dep_section|
36
40
  SectionConfig.new(dep_section)
@@ -10,17 +10,20 @@ module Bookbinder
10
10
  all_files_with_ext = file_system_accessor.find_files_with_ext('html', src)
11
11
 
12
12
  all_files_with_ext.map do |filepath|
13
- file_text = file_system_accessor.read filepath
13
+ file_text = file_system_accessor.read(filepath)
14
+
14
15
  file_title_text = html_document_manipulator.read_html_in_tag(document: file_text,
15
16
  tag: 'title')
16
17
 
17
18
  file_body_text = html_document_manipulator.read_html_in_tag(document: file_text,
18
19
  tag: 'body')
19
20
 
21
+ cleansed_body_text = revert_to_erb(file_body_text)
22
+
20
23
  relative_path_to_file = file_system_accessor.relative_path_from(src, filepath)
21
24
  new_filepath = File.join dest, "#{relative_path_to_file}.erb"
22
25
 
23
- output_text = frontmatter(file_title_text) + file_body_text
26
+ output_text = frontmatter(file_title_text) + cleansed_body_text
24
27
 
25
28
  file_system_accessor.write(to: new_filepath, text: output_text)
26
29
  end
@@ -34,6 +37,9 @@ module Bookbinder
34
37
  sanitized_title = title.gsub('"', '\"')
35
38
  "---\ntitle: \"#{sanitized_title}\"\ndita: true\n---\n"
36
39
  end
37
- end
38
40
 
41
+ def revert_to_erb(text)
42
+ text.gsub('&lt;%', '<%').gsub('%&gt;', '%>')
43
+ end
44
+ end
39
45
  end
@@ -39,6 +39,29 @@ module Bookbinder
39
39
  end
40
40
  end
41
41
 
42
+ def remote_tag(url, tagname, commit_or_object)
43
+ Dir.mktmpdir do |dir|
44
+ path = Pathname(dir)
45
+ git = cached_clone(url, temp_name("tag"), path)
46
+ git.config('user.name', 'Bookbinder')
47
+ git.config('user.email', 'bookbinder@cloudfoundry.org')
48
+ begin
49
+ git.add_tag(tagname, "origin/#{commit_or_object}",
50
+ message: 'Tagged by Bookbinder')
51
+ rescue Git::GitExecuteError => e
52
+ case e.message
53
+ when /already exists/
54
+ raise TagExists
55
+ when /as a valid ref/
56
+ raise InvalidTagRef
57
+ else
58
+ raise
59
+ end
60
+ end
61
+ git.push("origin", "master", tags: true)
62
+ end
63
+ end
64
+
42
65
  def author_date(path)
43
66
  Pathname(path).dirname.ascend do |current_dir|
44
67
  if current_dir.to_s.include?(source_dir_name) && current_dir.entries.include?(Pathname(".git"))
@@ -31,7 +31,8 @@ module Bookbinder
31
31
  section_config.desired_directory_name,
32
32
  section_config.subnav_template,
33
33
  section_config.subnav_name,
34
- section_config.preprocessor_config
34
+ section_config.preprocessor_config,
35
+ section_config.at_repo_path
35
36
  )
36
37
  end
37
38
  end
@@ -25,6 +25,7 @@ module Bookbinder
25
25
  template_variables: config.template_variables,
26
26
  local_repo_dir: local_repo_dir,
27
27
  workspace: output_locations.workspace_dir,
28
+ feedback_enabled: config.feedback_enabled
28
29
  }
29
30
  fs.write(to: "bookbinder_config.yml", text: YAML.dump(config))
30
31
  sheller.run_command({'MM_ROOT' => output_locations.master_dir.to_s},
@@ -38,7 +38,7 @@ module Bookbinder
38
38
  end
39
39
 
40
40
  dita_formatter.format_html(section_html_dir(section), formatted_dir(section))
41
- copy_images(section.path_to_repository, formatted_dir(section))
41
+ copy_images(section.path_to_repo_dir, formatted_dir(section))
42
42
  fs.copy_contents(formatted_dir(section), source_for_site_gen_dir(section))
43
43
  end
44
44
  end
@@ -10,13 +10,13 @@ module Bookbinder
10
10
  end
11
11
 
12
12
  def applicable_to?(section)
13
- filesystem.file_exist?(section.path_to_repository)
13
+ filesystem.file_exist?(section.path_to_repo_dir)
14
14
  end
15
15
 
16
16
  def preprocess(sections, output_locations, config: nil, **_)
17
17
  sections.each do |section|
18
18
  filesystem.link_creating_intermediate_dirs(
19
- section.path_to_repository,
19
+ section.path_to_repo_dir,
20
20
  output_locations.source_for_site_generator.join(section.destination_directory)
21
21
  )
22
22
  end
@@ -79,9 +79,6 @@ Found #{broken_links.count} broken links!
79
79
  Anemone.crawl(url) do |anemone|
80
80
  dont_visit_fragments(anemone)
81
81
  anemone.on_every_page do |page|
82
- if $sitemap_debug
83
- puts "\n\n********** Visiting page: #{page.url}\n\n#{page.body}"
84
- end
85
82
  broken, working = sieve.links_from Stabilimentum.new(page), is_first_pass
86
83
  broken_links.concat broken
87
84
  sitemap.concat working
@@ -7,9 +7,10 @@ module Bookbinder
7
7
  :desired_directory_name,
8
8
  :subnav_templ,
9
9
  :desired_subnav_name,
10
- :preprocessor_config) do
11
- def path_to_repository
12
- Pathname(self[:path_to_repository].to_s)
10
+ :preprocessor_config,
11
+ :at_repo_path) do
12
+ def path_to_repo_dir
13
+ at_repo_path.nil? ? path_to_repository : path_to_repository.join(at_repo_path)
13
14
  end
14
15
 
15
16
  def subnav_template
@@ -30,12 +31,19 @@ module Bookbinder
30
31
  end
31
32
 
32
33
  def path_to_preprocessor_attribute(attr)
33
- path_to_repository.join(preprocessor_config[attr]) if preprocessor_config[attr]
34
+ path_to_repo_dir.join(preprocessor_config[attr]) if preprocessor_config[attr]
34
35
  rescue NoMethodError => e
35
36
  raise Errors::ProgrammerMistake.new(
36
37
  "path_to_preprocessor_attribute assumes preprocessor_config is available, got nil.\n" +
37
38
  "Original exception:\n\n#{e.inspect}\n\n#{e.backtrace.join("\n")}"
38
39
  )
39
40
  end
41
+
42
+ private
43
+
44
+ def path_to_repository
45
+ Pathname(self[:path_to_repository].to_s)
46
+ end
47
+
40
48
  end
41
49
  end
@@ -54,6 +54,14 @@ module Bookbinder
54
54
  end
55
55
  end
56
56
 
57
+ def exclude_feedback
58
+ current_page.add_metadata({page: {feedback_disabled: true}})
59
+ end
60
+
61
+ def yield_for_feedback
62
+ partial 'layouts/feedback' if config[:feedback_enabled] && !current_page.metadata[:page][:feedback_disabled]
63
+ end
64
+
57
65
  def mermaid_diagram(&blk)
58
66
  escaped_text = capture(&blk).gsub('-','\-')
59
67
 
@@ -1,5 +1,9 @@
1
1
  require 'pathname'
2
- require 'vienna'
3
2
  require './rack_app'
4
- require './app'
5
- run Bookbinder::RackApp.new(Pathname('redirects.rb')).app
3
+ require './mail_sender'
4
+
5
+ mail_client = Bookbinder::MailSender.new(ENV['SENDGRID_USERNAME'],
6
+ ENV['SENDGRID_API_KEY'],
7
+ {to: ENV['FEEDBACK_TO'], from: ENV['FEEDBACK_FROM']})
8
+
9
+ run Bookbinder::RackApp.new(Pathname('redirects.rb'), mail_client).app
@@ -1,21 +1,23 @@
1
1
  require 'rack'
2
2
 
3
- class Rack::Static
4
- def route_file(path)
5
- @urls.kind_of?(Array) && @urls.any? { |url| url.index(path) == 0 }
6
- end
3
+ module Bookbinder
4
+ class RackStatic < Rack::Static
5
+ def route_file(path)
6
+ @urls.kind_of?(Array) && @urls.any? { |url| url.index(path) == 0 }
7
+ end
7
8
 
8
- def overwrite_file_path(path)
9
- path_has_trailing_slash?(path) && we_can_serve_index_at_path?(path)
10
- end
9
+ def overwrite_file_path(path)
10
+ path_has_trailing_slash?(path) && we_can_serve_index_at_path?(path)
11
+ end
11
12
 
12
- private
13
+ private
13
14
 
14
- def path_has_trailing_slash?(path)
15
- !((path =~ /\/$/).nil?)
16
- end
15
+ def path_has_trailing_slash?(path)
16
+ !((path =~ /\/$/).nil?)
17
+ end
17
18
 
18
- def we_can_serve_index_at_path?(path)
19
- @index && File.exists?(File.join @file_server.root, path, @index)
19
+ def we_can_serve_index_at_path?(path)
20
+ @index && File.exists?(File.join @file_server.root, path, @index)
21
+ end
20
22
  end
21
23
  end
@@ -1,28 +1,51 @@
1
- require 'vienna'
1
+ require_relative './rack_static'
2
2
 
3
- class Vienna::Application
4
- def initialize(root = 'public')
5
- @app = Rack::Builder.new do
6
- use Rack::Static, {
7
- urls: Dir.glob("#{root}/**/*").map { |fn| fn.gsub(/^#{root}/, '')},
8
- root: root,
9
- index: 'index.html',
10
- header_rules: [[:all, {'Cache-Control' => 'public, max-age=3600'}]]
11
- }
12
- run Vienna::NotFound.new("#{root}/404.html")
3
+ module Bookbinder
4
+ module Vienna
5
+ class << self
6
+ def call(env)
7
+ Application.new.call(env)
8
+ end
13
9
  end
14
- end
15
10
 
16
- def call(env)
17
- if env['PATH_INFO'] != '/' && env['PATH_INFO'] =~ MATCH
18
- env['PATH_INFO'] += '/'
19
- [301, {'Location' => Rack::Request.new(env).url, 'Content-Type' => ''}, []]
20
- else
21
- @app.call(env)
11
+ class Application
12
+ def initialize(root = 'public')
13
+ @app = Rack::Builder.new do
14
+ use RackStatic, {
15
+ urls: Dir.glob("#{root}/**/*").map { |fn| fn.gsub(/^#{root}/, '')},
16
+ root: root,
17
+ index: 'index.html',
18
+ header_rules: [[:all, {'Cache-Control' => 'public, max-age=3600'}]]
19
+ }
20
+ run NotFound.new("#{root}/404.html")
21
+ end
22
+ end
23
+
24
+ def call(env)
25
+ if env['PATH_INFO'] != '/' && env['PATH_INFO'] =~ MATCH
26
+ env['PATH_INFO'] += '/'
27
+ [301, {'Location' => Rack::Request.new(env).url, 'Content-Type' => ''}, []]
28
+ else
29
+ @app.call(env)
30
+ end
31
+ end
32
+
33
+ private
34
+ # regexp to match strings without periods that start and end with a slash
35
+ MATCH = %r{^/([^.]*)[^/]$}
22
36
  end
23
- end
24
37
 
25
- private
26
- # regexp to match strings without periods that start and end with a slash
27
- MATCH = %r{^/([^.]*)[^/]$}
38
+ class NotFound
39
+ def initialize(path = '')
40
+ @path = path
41
+ end
42
+
43
+ def call(env)
44
+ content = File.exist?(@path) ? File.read(@path) : 'Not Found'
45
+ length = content.length.to_s
46
+
47
+ [404, {'Content-Type' => 'text/html', 'Content-Length' => length}, [content]]
48
+ end
49
+ end
50
+ end
28
51
  end
@@ -0,0 +1,69 @@
1
+ require 'sendgrid-ruby'
2
+ require 'rack/response'
3
+ require 'uri'
4
+
5
+ module Bookbinder
6
+ class MailSender
7
+ def initialize(username, api_key, config={})
8
+ @config = config
9
+ @client = SendGrid::Client.new(api_user: username, api_key: api_key, raise_exceptions: false)
10
+ end
11
+
12
+ def send_mail(params)
13
+ params = whitelisted_params(params)
14
+ @subject = assemble_subject(params[:page_url])
15
+ @body = assemble_body(**params)
16
+ @mail = SendGrid::Mail.new(merged_options)
17
+
18
+ response = client.send(@mail)
19
+ Rack::Response.new(response.body, response.code, response.headers)
20
+ end
21
+
22
+ def assemble_subject(page_url)
23
+ "[Feedback] New feedback submitted for #{URI.parse(page_url).host}"
24
+ end
25
+
26
+ def assemble_body(helpful: nil, comments: nil, date: nil, page_url: nil)
27
+ <<-EOT
28
+ Dear docs writer,
29
+
30
+ You just received new feedback.
31
+
32
+ The sender thought the document was #{helpfulness(helpful)}.
33
+
34
+ Date: #{date}
35
+
36
+ Page URL: #{page_url}
37
+
38
+ Comments:
39
+ #{comments || "None given"}
40
+
41
+ Happy editing!
42
+ EOT
43
+ end
44
+
45
+ private
46
+
47
+ attr_reader :config, :client
48
+
49
+ def whitelist
50
+ %w{helpful comments date page_url}
51
+ end
52
+
53
+ def whitelisted_params(params)
54
+ {}.tap do |hash|
55
+ params.each do |key, value|
56
+ hash[key.to_sym] = value if whitelist.include?(key)
57
+ end
58
+ end
59
+ end
60
+
61
+ def merged_options
62
+ config.merge({text: @body, subject: @subject})
63
+ end
64
+
65
+ def helpfulness(was_helpful)
66
+ was_helpful ? 'helpful' : 'not helpful'
67
+ end
68
+ end
69
+ end
@@ -1,43 +1,82 @@
1
+ require 'rack'
1
2
  require 'rack/rewrite'
2
- require 'rack/auth/basic'
3
- require 'vienna'
3
+ require_relative './lib/vienna_application'
4
4
 
5
5
  module Bookbinder
6
6
  class RackApp
7
- def initialize(redirect_pathname, auth_required: true)
7
+ def initialize(redirect_pathname, mail_client=nil, auth_required: true)
8
8
  @redirect_pathname = redirect_pathname
9
+ @mail_client = mail_client
9
10
  @auth_required = auth_required
10
11
  end
11
12
 
12
13
  def app
13
- app = resolve_redirects
14
-
15
- if auth_required && site_username && site_password
16
- authorize_user(app)
17
- else
18
- app
14
+ path = redirect_pathname
15
+ client = mail_client
16
+ auth = auth_required
17
+ Rack::Builder.new(Vienna) do
18
+ use ResolveRedirects, path
19
+ use AuthorizeUser, auth
20
+ map '/api/feedback' do
21
+ use MailFeedback, client
22
+ run Vienna::NotFound.new('public/404.html')
23
+ end
19
24
  end
20
25
  end
21
26
 
22
27
  private
23
28
 
24
- attr_reader :redirect_pathname, :auth_required
29
+ attr_reader :redirect_pathname, :mail_client, :auth_required
30
+ end
31
+
32
+ class ResolveRedirects
33
+ def initialize(app, redirect_pathname)
34
+ @app = app
35
+ @redirect_pathname = redirect_pathname
36
+ end
25
37
 
26
- def resolve_redirects
38
+ def rack_app
27
39
  if redirect_pathname.exist?
28
40
  p = redirect_pathname
29
- Rack::Rewrite.new(Vienna) { eval(p.read) }
41
+ Rack::Rewrite.new(@app) { eval(p.read) }
30
42
  else
31
- Vienna
43
+ @app
32
44
  end
33
45
  end
34
46
 
35
- def authorize_user(app)
36
- Rack::Auth::Basic.new(app) do |username, password|
37
- [username, password] == [site_username, site_password]
47
+ def call(env)
48
+ rack_app.call(env)
49
+ end
50
+
51
+ private
52
+
53
+ attr_reader :redirect_pathname
54
+ end
55
+
56
+ class AuthorizeUser
57
+ def initialize(app, auth_required)
58
+ @app = app
59
+ @auth_required = auth_required
60
+ end
61
+
62
+ def rack_app
63
+ if auth_required && site_username && site_password
64
+ Rack::Auth::Basic.new(@app) do |username, password|
65
+ [username, password] == [site_username, site_password]
66
+ end
67
+ else
68
+ @app
38
69
  end
39
70
  end
40
71
 
72
+ def call(env)
73
+ rack_app.call(env)
74
+ end
75
+
76
+ private
77
+
78
+ attr_accessor :auth_required
79
+
41
80
  def site_username
42
81
  ENV['SITE_AUTH_USERNAME']
43
82
  end
@@ -46,4 +85,20 @@ module Bookbinder
46
85
  ENV['SITE_AUTH_PASSWORD']
47
86
  end
48
87
  end
88
+
89
+ class MailFeedback
90
+ def initialize(app, client)
91
+ @app = app
92
+ @client = client
93
+ end
94
+
95
+ def call(env)
96
+ request = Rack::Request.new(env)
97
+ if request.post? && @client
98
+ @client.send_mail(request.params)
99
+ else
100
+ @app.call(env)
101
+ end
102
+ end
103
+ end
49
104
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bookbindery
3
3
  version: !ruby/object:Gem::Version
4
- version: 7.2.0
4
+ version: 7.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Grafton
@@ -17,7 +17,7 @@ authors:
17
17
  autorequire:
18
18
  bindir: install_bin
19
19
  cert_chain: []
20
- date: 2015-10-23 00:00:00.000000000 Z
20
+ date: 2015-11-11 00:00:00.000000000 Z
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
23
23
  name: fog-aws
@@ -131,20 +131,6 @@ dependencies:
131
131
  - - "~>"
132
132
  - !ruby/object:Gem::Version
133
133
  version: 3.2.3
134
- - !ruby/object:Gem::Dependency
135
- name: vienna
136
- requirement: !ruby/object:Gem::Requirement
137
- requirements:
138
- - - '='
139
- - !ruby/object:Gem::Version
140
- version: 0.4.1
141
- type: :runtime
142
- prerelease: false
143
- version_requirements: !ruby/object:Gem::Requirement
144
- requirements:
145
- - - '='
146
- - !ruby/object:Gem::Version
147
- version: 0.4.1
148
134
  - !ruby/object:Gem::Dependency
149
135
  name: anemone
150
136
  requirement: !ruby/object:Gem::Requirement
@@ -229,6 +215,20 @@ dependencies:
229
215
  - - "~>"
230
216
  - !ruby/object:Gem::Version
231
217
  version: 1.2.8
218
+ - !ruby/object:Gem::Dependency
219
+ name: sendgrid-ruby
220
+ requirement: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ">="
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ type: :runtime
226
+ prerelease: false
227
+ version_requirements: !ruby/object:Gem::Requirement
228
+ requirements:
229
+ - - ">="
230
+ - !ruby/object:Gem::Version
231
+ version: '0'
232
232
  - !ruby/object:Gem::Dependency
233
233
  name: license_finder
234
234
  requirement: !ruby/object:Gem::Requirement
@@ -309,6 +309,7 @@ files:
309
309
  - lib/bookbinder/commands/generate.rb
310
310
  - lib/bookbinder/commands/help.rb
311
311
  - lib/bookbinder/commands/naming.rb
312
+ - lib/bookbinder/commands/punch.rb
312
313
  - lib/bookbinder/commands/push_from_local.rb
313
314
  - lib/bookbinder/commands/push_to_prod.rb
314
315
  - lib/bookbinder/commands/run_publish_ci.rb
@@ -387,12 +388,12 @@ files:
387
388
  - lib/bookbinder/values/section.rb
388
389
  - lib/bookbinder/values/subnav_template.rb
389
390
  - lib/bookbinder/values/user_message.rb
390
- - template_app/app.rb
391
391
  - template_app/config.ru
392
392
  - template_app/Gemfile
393
393
  - template_app/Gemfile.lock
394
394
  - template_app/lib/rack_static.rb
395
395
  - template_app/lib/vienna_application.rb
396
+ - template_app/mail_sender.rb
396
397
  - template_app/rack_app.rb
397
398
  - master_middleman/archive_drop_down_menu.rb
398
399
  - master_middleman/bookbinder_helpers.rb
data/template_app/app.rb DELETED
@@ -1,3 +0,0 @@
1
- exec("rackup -p #{ARGV[0] || 4567}") if require('vienna')
2
- require_relative 'lib/vienna_application'
3
- require_relative 'lib/rack_static'