bookwatch 1.0.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.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/bookwatch.gemspec +40 -0
  3. data/install_bin/bookwatch +5 -0
  4. data/lib/bookwatch/cli.rb +109 -0
  5. data/lib/bookwatch/code_example_reader.rb +95 -0
  6. data/lib/bookwatch/colorizer.rb +16 -0
  7. data/lib/bookwatch/commands/bind.rb +119 -0
  8. data/lib/bookwatch/commands/collection.rb +181 -0
  9. data/lib/bookwatch/commands/components/bind/directory_preparer.rb +33 -0
  10. data/lib/bookwatch/commands/components/bind/layout_preparer.rb +27 -0
  11. data/lib/bookwatch/commands/components/command_options.rb +45 -0
  12. data/lib/bookwatch/commands/components/imprint/directory_preparer.rb +24 -0
  13. data/lib/bookwatch/commands/generate.rb +92 -0
  14. data/lib/bookwatch/commands/imprint.rb +55 -0
  15. data/lib/bookwatch/commands/punch.rb +33 -0
  16. data/lib/bookwatch/commands/update_local_doc_repos.rb +42 -0
  17. data/lib/bookwatch/commands/watch.rb +100 -0
  18. data/lib/bookwatch/config/checkers/archive_menu_checker.rb +29 -0
  19. data/lib/bookwatch/config/checkers/ditamap_presence_checker.rb +27 -0
  20. data/lib/bookwatch/config/checkers/duplicate_section_name_checker.rb +33 -0
  21. data/lib/bookwatch/config/checkers/products_checker.rb +34 -0
  22. data/lib/bookwatch/config/checkers/repository_name_presence_checker.rb +34 -0
  23. data/lib/bookwatch/config/checkers/required_keys_checker.rb +18 -0
  24. data/lib/bookwatch/config/checkers/section_presence_checker.rb +15 -0
  25. data/lib/bookwatch/config/configuration.rb +119 -0
  26. data/lib/bookwatch/config/configuration_decorator.rb +54 -0
  27. data/lib/bookwatch/config/dita_config_generator.rb +61 -0
  28. data/lib/bookwatch/config/fetcher.rb +64 -0
  29. data/lib/bookwatch/config/imprint/configuration.rb +24 -0
  30. data/lib/bookwatch/config/product_config.rb +34 -0
  31. data/lib/bookwatch/config/section_config.rb +85 -0
  32. data/lib/bookwatch/config/validator.rb +33 -0
  33. data/lib/bookwatch/config/yaml_loader.rb +34 -0
  34. data/lib/bookwatch/css_link_checker.rb +67 -0
  35. data/lib/bookwatch/directory_helpers.rb +15 -0
  36. data/lib/bookwatch/dita_command_creator.rb +95 -0
  37. data/lib/bookwatch/dita_html_for_middleman_formatter.rb +45 -0
  38. data/lib/bookwatch/errors/programmer_mistake.rb +5 -0
  39. data/lib/bookwatch/html_document_manipulator.rb +21 -0
  40. data/lib/bookwatch/ingest/cloner_factory.rb +26 -0
  41. data/lib/bookwatch/ingest/destination_directory.rb +21 -0
  42. data/lib/bookwatch/ingest/git_accessor.rb +102 -0
  43. data/lib/bookwatch/ingest/git_cloner.rb +36 -0
  44. data/lib/bookwatch/ingest/local_filesystem_cloner.rb +66 -0
  45. data/lib/bookwatch/ingest/missing_working_copy.rb +27 -0
  46. data/lib/bookwatch/ingest/repo_identifier.rb +45 -0
  47. data/lib/bookwatch/ingest/section_repository.rb +49 -0
  48. data/lib/bookwatch/ingest/update_failure.rb +15 -0
  49. data/lib/bookwatch/ingest/update_success.rb +12 -0
  50. data/lib/bookwatch/ingest/working_copy.rb +36 -0
  51. data/lib/bookwatch/local_filesystem_accessor.rb +122 -0
  52. data/lib/bookwatch/middleman_runner.rb +48 -0
  53. data/lib/bookwatch/postprocessing/link_checker.rb +125 -0
  54. data/lib/bookwatch/postprocessing/redirection.rb +38 -0
  55. data/lib/bookwatch/preprocessing/dita_html_preprocessor.rb +91 -0
  56. data/lib/bookwatch/preprocessing/dita_pdf_preprocessor.rb +48 -0
  57. data/lib/bookwatch/preprocessing/link_to_site_gen_dir.rb +39 -0
  58. data/lib/bookwatch/preprocessing/preprocessor.rb +26 -0
  59. data/lib/bookwatch/server_director.rb +30 -0
  60. data/lib/bookwatch/sheller.rb +52 -0
  61. data/lib/bookwatch/streams/colorized_stream.rb +25 -0
  62. data/lib/bookwatch/streams/filter_stream.rb +22 -0
  63. data/lib/bookwatch/subnav/navigation_entries_from_html_toc.rb +59 -0
  64. data/lib/bookwatch/subnav/navigation_entries_from_markdown_root.rb +116 -0
  65. data/lib/bookwatch/subnav/pdf_config_creator.rb +50 -0
  66. data/lib/bookwatch/subnav/subnav_generator.rb +28 -0
  67. data/lib/bookwatch/subnav/subnav_generator_factory.rb +29 -0
  68. data/lib/bookwatch/subnav/template_creator.rb +71 -0
  69. data/lib/bookwatch/terminal.rb +19 -0
  70. data/lib/bookwatch/values/output_locations.rb +91 -0
  71. data/lib/bookwatch/values/product_info.rb +11 -0
  72. data/lib/bookwatch/values/section.rb +58 -0
  73. data/lib/bookwatch/values/subnav_template.rb +4 -0
  74. data/lib/bookwatch/values/user_message.rb +15 -0
  75. data/master_middleman/archive_drop_down_menu.rb +50 -0
  76. data/master_middleman/bookwatch_helpers.rb +259 -0
  77. data/master_middleman/compass_runner.rb +0 -0
  78. data/master_middleman/config.rb +34 -0
  79. data/master_middleman/quicklinks_renderer.rb +80 -0
  80. data/master_middleman/source/javascripts/all.js +2 -0
  81. data/master_middleman/source/javascripts/book.js +1 -0
  82. data/master_middleman/source/javascripts/bookwatch.js +103 -0
  83. data/master_middleman/source/layouts/_additional-scripts.erb +0 -0
  84. data/master_middleman/source/layouts/_book-footer.erb +0 -0
  85. data/master_middleman/source/layouts/_book-search.erb +0 -0
  86. data/master_middleman/source/layouts/_book-title.erb +3 -0
  87. data/master_middleman/source/layouts/_header.erb +34 -0
  88. data/master_middleman/source/layouts/_local-header.erb +0 -0
  89. data/master_middleman/source/layouts/_page-footer.erb +1 -0
  90. data/master_middleman/source/layouts/_title.erb +5 -0
  91. data/master_middleman/source/layouts/layout.erb +69 -0
  92. data/master_middleman/source/stylesheets/all.css.scss +3 -0
  93. data/master_middleman/source/stylesheets/base.scss +380 -0
  94. data/master_middleman/source/stylesheets/book-styles.css.scss +0 -0
  95. data/master_middleman/source/stylesheets/layout-styles.scss +0 -0
  96. data/master_middleman/source/stylesheets/partials/_book-base-values.scss +0 -0
  97. data/master_middleman/source/stylesheets/partials/_book-vars.scss +0 -0
  98. data/master_middleman/source/stylesheets/partials/_default.scss +300 -0
  99. data/master_middleman/source/stylesheets/partials/_footer.scss +64 -0
  100. data/master_middleman/source/stylesheets/partials/_header.scss +419 -0
  101. data/master_middleman/source/stylesheets/partials/_layout-vars.scss +0 -0
  102. data/master_middleman/source/stylesheets/partials/_mixins.scss +53 -0
  103. data/master_middleman/source/stylesheets/partials/_reset.scss +233 -0
  104. data/master_middleman/source/stylesheets/partials/_search.scss +78 -0
  105. data/master_middleman/source/stylesheets/partials/_sidenav.scss +191 -0
  106. data/master_middleman/source/stylesheets/partials/_syntax-highlight.scss +64 -0
  107. data/master_middleman/source/stylesheets/partials/_vars.scss +64 -0
  108. data/master_middleman/source/stylesheets/print.css.scss +58 -0
  109. data/master_middleman/source/subnavs/_default.erb +0 -0
  110. data/master_middleman/source/subnavs/_nav-links.erb +10 -0
  111. data/master_middleman/source/subnavs/_subnav_template.erb +8 -0
  112. data/master_middleman/subdirectory_aware_assets.rb +47 -0
  113. data/template_app/Gemfile +10 -0
  114. data/template_app/Gemfile.lock +43 -0
  115. data/template_app/config.ru +9 -0
  116. data/template_app/lib/rack_static_if_exists.rb +19 -0
  117. data/template_app/lib/search/handler.rb +47 -0
  118. data/template_app/lib/search/hit.rb +21 -0
  119. data/template_app/lib/search/query.rb +74 -0
  120. data/template_app/lib/search/renderer.rb +29 -0
  121. data/template_app/lib/server.rb +52 -0
  122. data/template_app/mail_sender.rb +69 -0
  123. data/template_app/rack_app.rb +110 -0
  124. data/template_app/search-results.html.erb +75 -0
  125. data/template_app/search.yml +22 -0
  126. metadata +491 -0
@@ -0,0 +1,64 @@
1
+ /*
2
+ * FILE: _syntax-highlight.scss
3
+ ======================================================================== */
4
+ pre .hll { background-color: #ffffcc; }
5
+ pre .c { color: #666666; font-style: italic; } // Comment
6
+ pre .err { color: #FF0000; background-color: #FFAAAA; } // Error
7
+ pre .k { color: #228899; font-weight: bold; } // Keyword
8
+ pre .o { color: #333333; } // Operator
9
+ pre .cm { color: #666666; font-style: italic; } // Comment.Multiline
10
+ pre .cp { color: #557799; } // Comment.Preproc
11
+ pre .c1 { color: #666666; font-style: italic; } // Comment.Single
12
+ pre .cs { color: #cc0000; font-weight: bold; font-style: italic; } // Comment.Special
13
+ pre .gd { color: #A00000; } // Generic.Deleted
14
+ pre .ge { font-style: italic; } // Generic.Emph
15
+ pre .gr { color: #FF0000; } // Generic.Error
16
+ pre .gh { color: #000080; font-weight: bold; } // Generic.Heading
17
+ pre .gi { color: #00A000; } // Generic.Inserted
18
+ pre .go { color: #888888; } // Generic.Output
19
+ pre .gp { color: #c65d09; font-weight: bold; } // Generic.Prompt
20
+ pre .gs { font-weight: bold; } // Generic.Strong
21
+ pre .gu { color: #800080; font-weight: bold; } // Generic.Subheading
22
+ pre .gt { color: #0044DD; } // Generic.Traceback
23
+ pre .kc { color: #228899; font-weight: bold; } // Keyword.Constant
24
+ pre .kd { color: #228899; font-weight: bold; } // Keyword.Declaration
25
+ pre .kn { color: #228899; font-weight: bold; } // Keyword.Namespace
26
+ pre .kp { color: #0088ff; font-weight: bold; } // Keyword.Pseudo
27
+ pre .kr { color: #228899; font-weight: bold; } // Keyword.Reserved
28
+ pre .kt { color: #6666ff; font-weight: bold; } // Keyword.Type
29
+ pre .m { color: #6600EE; font-weight: bold; } // Literal.Number
30
+ // pre .s { background-color: #F5F5FF; } // Literal.String
31
+ pre .na { color: #000077; } // Name.Attribute
32
+ pre .nb { color: #007722; } // Name.Builtin
33
+ pre .nc { color: #ee99ee; font-weight: bold; } // Name.Class
34
+ pre .no { color: #41AA9E; font-weight: bold; } // Name.Constant
35
+ pre .nd { color: #555555; font-weight: bold; } // Name.Decorator
36
+ pre .ni { color: #880000; } // Name.Entity
37
+ pre .ne { color: #FF0000; font-weight: bold; } // Name.Exception
38
+ pre .nf { color: #3E37DA; font-weight: bold; } // Name.Function
39
+ pre .nl { color: #997700; font-weight: bold; } // Name.Label
40
+ pre .nn { color: #0e84b5; font-weight: bold; } // Name.Namespace
41
+ pre .nt { color: #007700; } // Name.Tag
42
+ pre .nv { color: #003366; } // Name.Variable
43
+ pre .ow { color: #000000; font-weight: bold; } // Operator.Word
44
+ pre .w { color: #bbbbbb; } // Text.Whitespace
45
+ pre .mf { color: #6600EE; font-weight: bold; } // Literal.Number.Float
46
+ pre .mh { color: #005588; font-weight: bold; } // Literal.Number.Hex
47
+ pre .mi { color: #6666ff; font-weight: bold; } // Literal.Number.Integer
48
+ pre .mo { color: #4400EE; font-weight: bold; } // Literal.Number.Oct
49
+ pre .sb { background-color: #F5F5FF; } // Literal.String.Backtick
50
+ pre .sc { color: #8888FF; } // Literal.String.Char
51
+ pre .sd { color: #DD4422; } // Literal.String.Doc
52
+ pre .s2 { background-color: rgba(211, 211, 211, 0.2); } // Literal.String.Double
53
+ pre .se { color: #666666; font-weight: bold; background-color: #F5F5FF; } // Literal.String.Escape
54
+ pre .sh { background-color: #F5F5FF; } // Literal.String.Heredoc
55
+ pre .si { background-color: #eeeeee; } // Literal.String.Interpol
56
+ pre .sx { color: #ff8888; background-color: #F5F5FF; } // Literal.String.Other
57
+ pre .sr { color: #000000; background-color: #F5F5FF; } // Literal.String.Regex
58
+ pre .s1 { background-color: rgba(211, 211, 211, 0.2); } // Literal.String.Single
59
+ pre .ss { color: #D60F3F; } // Literal.String.Symbol
60
+ pre .bp { color: #007722; } // Name.Builtin.Pseudo
61
+ pre .vc { color: #ccccff; } // Name.Variable.Class
62
+ pre .vg { color: #ff8844; } // Name.Variable.Global
63
+ pre .vi { color: #aaaaff; } // Name.Variable.Instance
64
+ pre .il { color: #6666ff; font-weight: bold; } // Literal.Number.Integer.Long
@@ -0,0 +1,64 @@
1
+ $em-base: 16px !default;
2
+
3
+ // ~BEGIN BASE VALUES
4
+ // ===================================================
5
+ $font-primary: 'Source Sans Pro', sans-serif;
6
+ $font-size-xxl: 2.441em;
7
+ $font-size-xl: 1.953em;
8
+ $font-size-l: 1.563em;
9
+ $font-size-m: 1.25em;
10
+ $font-size-s: 1em;
11
+ $font-size-xs: 0.8em;
12
+
13
+ $gray1: #424242;
14
+ $gray2: #686868;
15
+ $gray3: #b5b5b5;
16
+ $gray4: #eceae9;
17
+ $gray5: #f8f8f8;
18
+ $gray6: #fdfdfd;
19
+
20
+ // Book-specific overrides
21
+ @import "book-base-values.scss";
22
+
23
+ $color-accent: $gray6;
24
+ $color-accent-bright: $gray6;
25
+ $color-accent-bright-contrast: #000000;
26
+
27
+ // text colors
28
+ $color-header: $gray2;
29
+ $color-text: $gray1;
30
+ $color-text-dim: $gray3;
31
+
32
+ // link colors
33
+ $color-link: #b5292e;
34
+ $color-link-border: #154896;
35
+
36
+ // border colors
37
+ $color-border-row: $gray5;
38
+ $color-border: $gray4;
39
+ $color-border-light: $gray4;
40
+ $color-border-superlight: $gray4;
41
+ $color-border-dark: $gray3;
42
+ $color-border-tip: $gray1;
43
+
44
+ // background-colors
45
+ $color-bg: $gray5;
46
+ $color-bg-light: $gray6;
47
+ $color-bg-panel: $gray5;
48
+ $color-bg-header: #b625ff;
49
+ $color-bg-dark: #523f74;
50
+
51
+ // ~SIZES
52
+ // ===================================================
53
+ $radius: 3px;
54
+ $sidenav-wide: 278px/$em-base + 0em;
55
+ $sidenav-widest: 367px/$em-base + 0em;
56
+
57
+ // ~BREAKPOINTS
58
+ // ===================================================
59
+ $bp-superwide: 1340px/$em-base + 0em;
60
+ $bp-widest: 900px/$em-base + 0em;
61
+ $bp-wide: 700px/$em-base + 0em;
62
+
63
+ @import "layout-vars.scss";
64
+ @import "book-vars.scss";
@@ -0,0 +1,58 @@
1
+ /*
2
+ * FILE: print.scss
3
+ ======================================================================== */
4
+ @import "partials/_vars.scss";
5
+
6
+ // Book-specific overrides
7
+ @import "partials/_book-vars.scss";
8
+
9
+ pre code, p code, .terminal {
10
+ font-family: "DejaVu Sans Mono";
11
+ page-break-inside: avoid;
12
+ }
13
+
14
+ ol li {
15
+ margin-left: 15px;
16
+ }
17
+
18
+ .wrap {
19
+ width: 2400px;
20
+
21
+ .container {
22
+ margin-left: 0;
23
+ }
24
+ }
25
+
26
+ li p code {
27
+ width: auto;
28
+ display: inline;
29
+ }
30
+
31
+ note {
32
+ overflow: visible;
33
+ page-break-inside: avoid !important;
34
+ page-break-before: avoid !important;
35
+ }
36
+
37
+ pre, pre code {
38
+ overflow: visible;
39
+ }
40
+
41
+ .pivotalcf .logo {
42
+ background: none;
43
+ padding-left: 0;
44
+ }
45
+
46
+ .quick-links,
47
+ .nav-container,
48
+ .header,
49
+ .site-footer-links,
50
+ #feedback {
51
+ display: none;
52
+ }
53
+
54
+ h1 {
55
+ margin-top: 0;
56
+ font-size: $font-size-l;
57
+ }
58
+
@@ -0,0 +1,10 @@
1
+ <% unless links?(@links) %>
2
+ <ul>
3
+ <% @links.each do |link| %>
4
+ <li class="<%= submenu_class(link) %>">
5
+ <a href="<%= link[:url] %>"><%= escape_html link[:text] %></a>
6
+ <%= render_links link[:nested_links] %>
7
+ </li>
8
+ <% end %>
9
+ </ul>
10
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <div id="sub-nav" class="nav-container js-sidenav" role="navigation" >
2
+ <a class="sidenav-title" data-behavior="SubMenuMobile">
3
+ Doc Index
4
+ </a>
5
+ <div class="nav-content">
6
+ <%= render_links @links %>
7
+ </div>
8
+ </div>
@@ -0,0 +1,47 @@
1
+ class SubdirectoryAwareAssets < ::Middleman::Extension
2
+ def initialize(app, options_hash={}, &block)
3
+ super
4
+
5
+ # After compass is setup, make it use the registered cache buster
6
+ app.compass_config do |config|
7
+ config.relative_assets = true
8
+ end if app.respond_to?(:compass_config)
9
+ end
10
+
11
+ helpers do
12
+ def asset_url(path, prefix="", options={})
13
+ url = super(path, prefix, options)
14
+
15
+ unless global_asset_at? url
16
+ current_dir = Pathname('/' + current_resource.destination_path)
17
+ url = Pathname(url).relative_path_from(current_dir.dirname).to_s
18
+ end
19
+
20
+ # middleman assumes your assets live at the top level, but they may be in the nested repos instead
21
+ # here we start at top level and dive down until we find the real asset
22
+ current_page_path_parts = current_resource.destination_path.split('/')
23
+ current_page_path_parts.pop
24
+ current_page_dir = File.join('source', current_page_path_parts, '')
25
+ while (!File.exists? "#{current_page_dir}#{url}") && url.match(/^\.\.\//) do
26
+ url = url.gsub(/^\.\.\//, "")
27
+ end
28
+
29
+ url
30
+ end
31
+
32
+ private
33
+
34
+ def global_asset_at?(path)
35
+ path.include?('//') ||
36
+ path.start_with?('data:') ||
37
+ !current_resource ||
38
+ path.index('.css') ||
39
+ path.index('.js')
40
+ end
41
+ end
42
+
43
+ end
44
+
45
+ ::Middleman::Extensions.register(:subdirectory_aware_assets, SubdirectoryAwareAssets)
46
+
47
+
@@ -0,0 +1,10 @@
1
+ source 'http://rubygems.org'
2
+
3
+ ruby '2.3.0'
4
+
5
+ gem 'rack'
6
+ gem 'rack-rewrite'
7
+ gem 'puma'
8
+ gem 'therubyracer'
9
+ gem 'sendgrid-ruby', '< 3.0'
10
+ gem 'elasticsearch'
@@ -0,0 +1,43 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ elasticsearch (1.0.17)
5
+ elasticsearch-api (= 1.0.17)
6
+ elasticsearch-transport (= 1.0.17)
7
+ elasticsearch-api (1.0.17)
8
+ multi_json
9
+ elasticsearch-transport (1.0.17)
10
+ faraday
11
+ multi_json
12
+ faraday (0.9.2)
13
+ multipart-post (>= 1.2, < 3)
14
+ libv8 (3.16.14.7)
15
+ mimemagic (0.3.0)
16
+ multi_json (1.11.2)
17
+ multipart-post (2.0.0)
18
+ puma (3.3.0)
19
+ rack (1.5.2)
20
+ rack-rewrite (1.5.0)
21
+ ref (1.0.5)
22
+ sendgrid-ruby (1.1.5)
23
+ faraday (~> 0.9)
24
+ mimemagic
25
+ smtpapi (~> 0.1)
26
+ smtpapi (0.1.0)
27
+ therubyracer (0.12.1)
28
+ libv8 (~> 3.16.14.0)
29
+ ref
30
+
31
+ PLATFORMS
32
+ ruby
33
+
34
+ DEPENDENCIES
35
+ elasticsearch
36
+ puma
37
+ rack
38
+ rack-rewrite
39
+ sendgrid-ruby (< 3.0)
40
+ therubyracer
41
+
42
+ BUNDLED WITH
43
+ 1.11.2
@@ -0,0 +1,9 @@
1
+ require 'pathname'
2
+ require './rack_app'
3
+ require './mail_sender'
4
+
5
+ mail_client = Bookwatch::MailSender.new(ENV['SENDGRID_USERNAME'],
6
+ ENV['SENDGRID_API_KEY'],
7
+ {to: ENV['FEEDBACK_TO'], from: ENV['FEEDBACK_FROM']})
8
+
9
+ run Bookwatch::RackApp.new(Pathname('redirects.rb'), mail_client).app
@@ -0,0 +1,19 @@
1
+ require 'rack'
2
+
3
+ module Bookwatch
4
+ class RackStaticIfExists < Rack::Static
5
+ def can_serve(path)
6
+ file_exists?(path) || dir_with_index_exists?(path)
7
+ end
8
+
9
+ private
10
+
11
+ def file_exists?(path)
12
+ File.file?(File.join(@file_server.root, path))
13
+ end
14
+
15
+ def dir_with_index_exists?(path)
16
+ File.directory?(File.join(@file_server.root, path)) && !!@index && file_exists?(File.join(path, @index))
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,47 @@
1
+ require 'elasticsearch'
2
+ require 'cgi'
3
+ require 'json'
4
+
5
+ require_relative 'query'
6
+ require_relative 'renderer'
7
+
8
+ module Bookwatch
9
+ module Search
10
+ class Handler
11
+ def initialize(client_class = Elasticsearch::Client, environment = ENV)
12
+ @client_class = client_class
13
+ @environment = environment
14
+ @renderer = Renderer.new
15
+ end
16
+
17
+ def call(request_env)
18
+ query = Query.new(extract_query_params(request_env['QUERY_STRING']))
19
+ query.get_results(client_class.new(url: elasticsearch_url))
20
+
21
+ [200, {'Content-Type' => 'text/html'}, [renderer.render_results(query)]]
22
+ rescue Exception => e
23
+ puts e.message
24
+ puts e.backtrace.join("\n")
25
+
26
+ [500, {'Content-Type' => 'text/plain'}, ['An error occurred']]
27
+ end
28
+
29
+ def extract_query_params(param_string)
30
+ parsed = CGI::parse(param_string || '')
31
+ parsed.keys.inject(Hash.new('')) do |params, key|
32
+ # CGI::parse returns values in an array
33
+ params[key] = parsed[key].first
34
+ params
35
+ end
36
+ end
37
+
38
+ private
39
+
40
+ attr_reader :renderer, :client_class, :environment
41
+
42
+ def elasticsearch_url
43
+ @elasticsearch_url ||= JSON.parse(environment['VCAP_SERVICES'])['searchly'][0]['credentials']['uri']
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,21 @@
1
+ module Bookwatch
2
+ module Search
3
+ class Hit
4
+ def initialize(attrs = {})
5
+ source_fields = attrs.fetch('_source')
6
+ @title = source_fields.fetch('title').sub(/\A(.+)\|.*\z/, '\\1').strip
7
+ @url = source_fields.fetch('url')
8
+ @product_name = source_fields['product_name']
9
+ @product_version = source_fields['product_version']
10
+
11
+ if attrs.has_key?('highlight')
12
+ @text = attrs.fetch('highlight').fetch('text').first.strip
13
+ else
14
+ @text = source_fields.fetch('summary')
15
+ end
16
+ end
17
+
18
+ attr_reader :title, :url, :text, :product_name, :product_version
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,74 @@
1
+ require 'yaml'
2
+
3
+ require_relative 'hit'
4
+
5
+ module Bookwatch
6
+ module Search
7
+ class Query
8
+ attr_reader :search_term, :product_name, :product_version, :page_number, :result_list, :result_count, :last_page, :page_window
9
+
10
+ def initialize(params)
11
+ @search_term = params.fetch('q', '')
12
+ @product_name = params.fetch('product_name', nil)
13
+ @product_version = @product_name && params.fetch('product_version', nil)
14
+ @page_number = @search_term == '' ? 1 : [params['page'].to_i, 1].max
15
+ end
16
+
17
+ def query_options
18
+ options = YAML.load_file(File.expand_path('../../../search.yml', __FILE__))
19
+
20
+ options['from'] = (page_number - 1) * 10
21
+ options['query']['bool']['should']['simple_query_string']['query'] = search_term
22
+
23
+ unless product_name.nil?
24
+ filters = [{
25
+ 'term' => { 'product_name' => product_name }
26
+ }]
27
+
28
+ unless product_version.nil?
29
+ filters << {'term' => { 'product_version' => product_version }}
30
+ end
31
+
32
+ options['query']['bool']['filter'] = {
33
+ 'bool' => {
34
+ 'must' => filters
35
+ }
36
+ }
37
+ end
38
+
39
+ options
40
+ end
41
+
42
+ def get_results(elasticsearch_client)
43
+ if search_term == ''
44
+ @result_count = 0
45
+ @result_list = []
46
+ @last_page = 1
47
+ else
48
+ results = elasticsearch_client.search index: 'searching', body: query_options
49
+ @result_count = results['hits']['total']
50
+ @result_list = results['hits']['hits'].map { |h| Hit.new(h) }
51
+ @last_page = (result_count / 10.0).ceil
52
+ end
53
+ @page_window = calculate_page_window
54
+ end
55
+
56
+ private
57
+
58
+ def calculate_page_window
59
+ window_start = [page_number - 2, 1].max
60
+ window_end = [window_start + 4, last_page].min
61
+ window = (window_start .. window_end).to_a
62
+
63
+ if window.length < 5 && window.last == last_page && window.first != 1
64
+ window.unshift(window.first - 1)
65
+ if window.length < 5
66
+ window.unshift(window.first - 1)
67
+ end
68
+ end
69
+
70
+ window
71
+ end
72
+ end
73
+ end
74
+ end