bookbindery 7.2.0 → 7.3.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
  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'