bookwatch 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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