quick_search-core 0.0.1.test
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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +168 -0
- data/Rakefile +6 -0
- data/app/assets/images/quick_search/askus.gif +0 -0
- data/app/assets/images/quick_search/favicon.ico +0 -0
- data/app/assets/images/quick_search/greybox.png +0 -0
- data/app/assets/images/quick_search/homescreen-icon-64x64.png +0 -0
- data/app/assets/images/quick_search/ncsu-library-logo-white.png +0 -0
- data/app/assets/javascripts/quick_search/appstats.js +8 -0
- data/app/assets/javascripts/quick_search/event_tracking.js.erb +257 -0
- data/app/assets/javascripts/quick_search/google_analytics.js.erb +8 -0
- data/app/assets/javascripts/quick_search/opensearch.js +2 -0
- data/app/assets/javascripts/quick_search/pages.js.coffee +3 -0
- data/app/assets/javascripts/quick_search/quicksearch.js +33 -0
- data/app/assets/javascripts/quick_search/realtime.js.erb +12 -0
- data/app/assets/javascripts/quick_search/search.js +3 -0
- data/app/assets/javascripts/quick_search/xhr_search.js +82 -0
- data/app/assets/javascripts/quick_search.js.erb +20 -0
- data/app/assets/stylesheets/foundation_and_overrides.scss +1327 -0
- data/app/assets/stylesheets/quick_search/appstats.css.scss +7 -0
- data/app/assets/stylesheets/quick_search/opensearch.css.scss +3 -0
- data/app/assets/stylesheets/quick_search/pages.css.scss +3 -0
- data/app/assets/stylesheets/quick_search/quick_search.css.scss +248 -0
- data/app/assets/stylesheets/quick_search/search.css.scss +3 -0
- data/app/assets/stylesheets/quick_search.css.scss.erb +7 -0
- data/app/controllers/concerns/quick_search/auth.rb +22 -0
- data/app/controllers/concerns/quick_search/doi_trap.rb +43 -0
- data/app/controllers/concerns/quick_search/encode_utf8.rb +12 -0
- data/app/controllers/concerns/quick_search/on_campus.rb +43 -0
- data/app/controllers/concerns/quick_search/query_filter.rb +25 -0
- data/app/controllers/concerns/quick_search/query_parser.rb +54 -0
- data/app/controllers/concerns/quick_search/searcher_concern.rb +101 -0
- data/app/controllers/concerns/quick_search/searcher_config.rb +16 -0
- data/app/controllers/quick_search/application_controller.rb +7 -0
- data/app/controllers/quick_search/appstats_controller.rb +210 -0
- data/app/controllers/quick_search/opensearch_controller.rb +9 -0
- data/app/controllers/quick_search/pages_controller.rb +18 -0
- data/app/controllers/quick_search/search_controller.rb +250 -0
- data/app/helpers/quick_search/application_helper.rb +68 -0
- data/app/helpers/quick_search/appstats_helper.rb +2 -0
- data/app/helpers/quick_search/opensearch_helper.rb +2 -0
- data/app/helpers/quick_search/pages_helper.rb +2 -0
- data/app/helpers/quick_search/search_helper.rb +2 -0
- data/app/models/event.rb +2 -0
- data/app/models/search.rb +11 -0
- data/app/searchers/quick_search/best_bets_searcher.rb +102 -0
- data/app/searchers/quick_search/searcher.rb +43 -0
- data/app/views/layouts/quick_search/_best_bets.html.erb +18 -0
- data/app/views/layouts/quick_search/_common_searches.html.erb +15 -0
- data/app/views/layouts/quick_search/_found_types.html.erb +13 -0
- data/app/views/layouts/quick_search/_google_analytics.html.erb +24 -0
- data/app/views/layouts/quick_search/_more_options.html.erb +10 -0
- data/app/views/layouts/quick_search/_page_title.html.erb +8 -0
- data/app/views/layouts/quick_search/_related_topics.html.erb +8 -0
- data/app/views/layouts/quick_search/_search_form.html.erb +19 -0
- data/app/views/layouts/quick_search/_spelling_suggestion.html.erb +13 -0
- data/app/views/layouts/quick_search/_topic_snippet.html.erb +5 -0
- data/app/views/layouts/quick_search/application.html.erb +40 -0
- data/app/views/quick_search/appstats/_click_count_table.html.erb +23 -0
- data/app/views/quick_search/appstats/_datatables.html.erb +12 -0
- data/app/views/quick_search/appstats/_date_range.html.erb +15 -0
- data/app/views/quick_search/appstats/_menu.html.erb +16 -0
- data/app/views/quick_search/appstats/_top_spot_report_table.html.erb +33 -0
- data/app/views/quick_search/appstats/clicks_overview.html.erb +20 -0
- data/app/views/quick_search/appstats/index.html.erb +31 -0
- data/app/views/quick_search/appstats/module_click_detail.html.erb +32 -0
- data/app/views/quick_search/appstats/realtime.html.erb +15 -0
- data/app/views/quick_search/appstats/top_searches.html.erb +38 -0
- data/app/views/quick_search/appstats/top_spot.html.erb +14 -0
- data/app/views/quick_search/appstats/top_spot_detail.html.erb +35 -0
- data/app/views/quick_search/kaminari/_first_page.html.erb +12 -0
- data/app/views/quick_search/kaminari/_gap.html.erb +11 -0
- data/app/views/quick_search/kaminari/_last_page.html.erb +12 -0
- data/app/views/quick_search/kaminari/_next_page.html.erb +12 -0
- data/app/views/quick_search/kaminari/_page.html.erb +13 -0
- data/app/views/quick_search/kaminari/_paginator.html.erb +25 -0
- data/app/views/quick_search/kaminari/_prev_page.html.erb +11 -0
- data/app/views/quick_search/opensearch/opensearch.xml.builder +11 -0
- data/app/views/quick_search/pages/about.html.erb +9 -0
- data/app/views/quick_search/pages/home.html.erb +6 -0
- data/app/views/quick_search/pages/realtime.html.erb +15 -0
- data/app/views/quick_search/search/_citation.html.erb +18 -0
- data/app/views/quick_search/search/_module.html.erb +37 -0
- data/app/views/quick_search/search/_module_with_paging.html.erb +14 -0
- data/app/views/quick_search/search/_no_results.html.erb +11 -0
- data/app/views/quick_search/search/_result.html.erb +17 -0
- data/app/views/quick_search/search/_result_details.html.erb +45 -0
- data/app/views/quick_search/search/_result_no_thumbnail.html.erb +3 -0
- data/app/views/quick_search/search/_result_title.html.erb +4 -0
- data/app/views/quick_search/search/_result_with_thumbnail.html.erb +21 -0
- data/app/views/quick_search/search/_search_error.html.erb +9 -0
- data/app/views/quick_search/search/_see_all.html.erb +11 -0
- data/app/views/quick_search/search/_xhr_response.html.erb +15 -0
- data/app/views/quick_search/search/_xhr_response.json.erb +14 -0
- data/app/views/quick_search/search/_xhr_response_with_paging.html.erb +1 -0
- data/app/views/quick_search/search/index.html.erb +100 -0
- data/config/application.rb +25 -0
- data/config/best_bets.yml +86 -0
- data/config/boot.rb +4 -0
- data/config/database.yml.example +31 -0
- data/config/locales/en.yml +30 -0
- data/config/quicksearch_config.yml.example +69 -0
- data/config/routes.rb +81 -0
- data/db/migrate/20140130202859_create_events.rb +11 -0
- data/db/migrate/20140130202944_create_searches.rb +9 -0
- data/db/migrate/20140225145441_add_page_to_searches.rb +5 -0
- data/db/schema.rb +31 -0
- data/db/seeds.rb +7 -0
- data/lib/benchmark_logger.rb +2 -0
- data/lib/capistrano/tasks/access_check.cap +10 -0
- data/lib/generators/quick_search/install_generator.rb +49 -0
- data/lib/generators/quick_search/templates/kaminari.rb +5 -0
- data/lib/generators/quick_search/templates/post_install.txt +8 -0
- data/lib/generators/quick_search/templates/quick_search_config.yml +58 -0
- data/lib/quick_search/engine.rb +16 -0
- data/lib/quick_search/version.rb +3 -0
- data/lib/quick_search.rb +12 -0
- data/lib/tasks/best_bets.rake +29 -0
- data/test/controllers/appstats_controller_test.rb +7 -0
- data/test/controllers/concerns/doi_trap_test.rb +19 -0
- data/test/controllers/concerns/on_campus_test.rb +19 -0
- data/test/controllers/concerns/query_parser_test.rb +47 -0
- data/test/controllers/opensearch_controller_test.rb +13 -0
- data/test/controllers/pages_controller_test.rb +7 -0
- data/test/controllers/search_controller_test.rb +15 -0
- data/test/fixtures/events.yml +11 -0
- data/test/fixtures/searches.yml +7 -0
- data/test/helpers/appstats_helper_test.rb +4 -0
- data/test/helpers/opensearch_helper_test.rb +4 -0
- data/test/helpers/pages_helper_test.rb +4 -0
- data/test/helpers/search_helper_test.rb +4 -0
- data/test/integration/catalog_search_test.rb +8 -0
- data/test/integration/google_analytics_test.rb +23 -0
- data/test/integration/landing_page_test.rb +8 -0
- data/test/integration/searching_test.rb +40 -0
- data/test/integration/smart_subjects_test.rb +8 -0
- data/test/integration/website_search_test.rb +8 -0
- data/test/models/event_test.rb +7 -0
- data/test/models/search_test.rb +7 -0
- data/test/searcher/best_bets_test.rb +35 -0
- data/test/searcher/catalog_test.rb +35 -0
- data/test/searcher/ematrix_database_test.rb +27 -0
- data/test/searcher/ematrix_journal_test.rb +27 -0
- data/test/searcher/faq_test.rb +27 -0
- data/test/searcher/smart_subjects_test.rb +27 -0
- data/test/searcher/summon_test.rb +13 -0
- data/test/searcher/website_test.rb +34 -0
- data/test/support/vcr_test.rb +40 -0
- data/test/test_helper.rb +42 -0
- metadata +366 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
@mixin text-badge {
|
|
2
|
+
padding: 1px 5px 2px 5px;
|
|
3
|
+
border-radius: 2px;
|
|
4
|
+
color: #FFF;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
//element overrides
|
|
8
|
+
#content {
|
|
9
|
+
#main-content {
|
|
10
|
+
#quicksearch {
|
|
11
|
+
|
|
12
|
+
.twitter-typeahead {
|
|
13
|
+
width: 100%;
|
|
14
|
+
|
|
15
|
+
img {
|
|
16
|
+
max-width: 79.578125px;
|
|
17
|
+
}
|
|
18
|
+
.space-container {
|
|
19
|
+
max-width: 438.3125px;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.bestbet-container {
|
|
23
|
+
padding: 0;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
h3 {
|
|
29
|
+
padding-top: 0;
|
|
30
|
+
font-weight: normal;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
ol, ul {
|
|
34
|
+
margin-left: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
li {
|
|
38
|
+
list-style-type: none;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
em {
|
|
42
|
+
font-style: normal;
|
|
43
|
+
font-weight: bold;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
#website {
|
|
47
|
+
margin-bottom: 2.5em;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// class overrides
|
|
51
|
+
|
|
52
|
+
.prefix.button {
|
|
53
|
+
height: 2.3rem
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
@media only screen and (max-width: 766px) {
|
|
57
|
+
.prefix.button {
|
|
58
|
+
height: 2.76rem
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
input[type="text"] {
|
|
63
|
+
-webkit-appearance: none;
|
|
64
|
+
border-radius: 0;
|
|
65
|
+
font-size: 1rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
input[type="search"] {
|
|
69
|
+
margin: 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// custom classes
|
|
73
|
+
|
|
74
|
+
.about {
|
|
75
|
+
float: right;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
.result-types {
|
|
79
|
+
margin: 10px 0 0 0;
|
|
80
|
+
li {
|
|
81
|
+
margin: 0 20px 0 0;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.trying_again {
|
|
86
|
+
padding-bottom: 20px;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.clear-search-box {
|
|
90
|
+
display: none;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.title {
|
|
94
|
+
font-size: 1.25em;
|
|
95
|
+
margin-bottom:0;
|
|
96
|
+
margin-top: 1em;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.result {
|
|
100
|
+
p {
|
|
101
|
+
margin-bottom: 0;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.see-all-results {
|
|
106
|
+
margin-bottom: 2.5em;
|
|
107
|
+
margin-top: 2em;
|
|
108
|
+
font-weight: bold;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.search-error-message {
|
|
112
|
+
margin-top: 1em
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.with-thumbnail {
|
|
116
|
+
margin-bottom: 0.9em;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.no-thumbnail {
|
|
120
|
+
margin-bottom: 0.9em;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.link {
|
|
124
|
+
display: none;
|
|
125
|
+
word-break: break-word;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.query {
|
|
129
|
+
font-weight: bold;
|
|
130
|
+
word-break: break-word;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.display-link {
|
|
134
|
+
word-break: break-all;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.highlight {
|
|
138
|
+
@include text-badge;
|
|
139
|
+
background: #edb802;
|
|
140
|
+
@media only screen and (max-width: 640px) {
|
|
141
|
+
display: none;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.result-types-highlight {
|
|
146
|
+
@media only screen and (max-width: 640px) {
|
|
147
|
+
display: none;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.available {
|
|
152
|
+
color: #090;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.unavailable {
|
|
156
|
+
color: #C00;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.section-description {
|
|
160
|
+
text-transform: none;
|
|
161
|
+
margin-top: 1em;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.side-bar {
|
|
165
|
+
span.total {
|
|
166
|
+
display: none;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.thumbnail {
|
|
171
|
+
border: 1px solid #555555;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.citation {
|
|
175
|
+
.publisher {
|
|
176
|
+
font-style: italic;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.date {
|
|
181
|
+
font-weight: normal;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.search-error-rescue {
|
|
185
|
+
display: none;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.website {
|
|
189
|
+
.link {
|
|
190
|
+
display: block;
|
|
191
|
+
color: #006621;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.summon {
|
|
196
|
+
.description {
|
|
197
|
+
display: none;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
.faq {
|
|
203
|
+
.total {
|
|
204
|
+
display: none;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
.related-topics {
|
|
210
|
+
ul {
|
|
211
|
+
column-count: 2;
|
|
212
|
+
-moz-column-count: 2; /* Firefox */
|
|
213
|
+
-webkit-column-count: 2; /* Safari and Chrome */
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.journals-databases, .faq {
|
|
218
|
+
h3 {
|
|
219
|
+
font-size: 1.1em;
|
|
220
|
+
}
|
|
221
|
+
li {
|
|
222
|
+
margin-bottom: 0;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.appstats-show {
|
|
227
|
+
.total {
|
|
228
|
+
font-weight: bold;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
// hide google analytics debug
|
|
237
|
+
|
|
238
|
+
#quicksearch-ga-debug {
|
|
239
|
+
display: none;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// .hidden {
|
|
243
|
+
// display: none;
|
|
244
|
+
// }
|
|
245
|
+
|
|
246
|
+
.feedback-form {
|
|
247
|
+
display: none;
|
|
248
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
require "digest/md5"
|
|
2
|
+
|
|
3
|
+
module QuickSearch::Auth
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
SALT01 = SecureRandom.hex(512)
|
|
7
|
+
SALT02 = SecureRandom.hex(512)
|
|
8
|
+
REALM = "Please enter the username and password to access this page"
|
|
9
|
+
USERS = {"#{QuickSearch::Engine::APP_CONFIG['user']}" => Digest::MD5.hexdigest(["#{QuickSearch::Engine::APP_CONFIG['user']}",REALM,"#{QuickSearch::Engine::APP_CONFIG['password']}"].join(":"))}
|
|
10
|
+
SALTY = SALT01 + Digest::MD5.hexdigest(["#{QuickSearch::Engine::APP_CONFIG['user']}",REALM,"#{QuickSearch::Engine::APP_CONFIG['password']}"].join(":")) + SALT02
|
|
11
|
+
|
|
12
|
+
def auth
|
|
13
|
+
authenticate_or_request_with_http_digest(REALM) do |username|
|
|
14
|
+
unless SALT01.blank? or SALT02.blank? or USERS[username].blank?
|
|
15
|
+
if SALT01 + USERS[username] + SALT02 == SALTY
|
|
16
|
+
USERS[username]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module QuickSearch::DoiTrap
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
include QuickSearch::EncodeUtf8
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def doi_trap
|
|
9
|
+
unless params_q_scrubbed.nil?
|
|
10
|
+
if is_a_doi?(doi_query)
|
|
11
|
+
Event.create(category: 'doi-trap', action: doi_query, label: '')
|
|
12
|
+
redirect_to doi_loaded_link
|
|
13
|
+
# Alternately insert a loaded link into the results interface
|
|
14
|
+
# @doi_loaded_link = loaded_link
|
|
15
|
+
# @doi_callout = "Searching for a DOI? Try this: "
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def is_a_doi?(query)
|
|
21
|
+
if doi_regex.match(query)
|
|
22
|
+
true
|
|
23
|
+
else
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def doi_regex
|
|
29
|
+
/^(?:(?:doi:?\s*|(?:http:\/\/)?(?:dx\.)?(?:doi\.org)?\/))?(10(?:\.\d+){1,2}\/\S+)$/i
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def doi_loaded_link
|
|
33
|
+
QuickSearch::Engine::APP_CONFIG['doi_loaded_link'] + CGI.escape(doi_regex.match(doi_query)[1])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def doi_query
|
|
37
|
+
query = params_q_scrubbed
|
|
38
|
+
query.strip!
|
|
39
|
+
query.squish!
|
|
40
|
+
query
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module QuickSearch::OnCampus
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
# Search for "Nucleation and growth mechanism of ferroelectric domain wall motion"
|
|
7
|
+
# To test this. Result should not show up in Summon results off campus.
|
|
8
|
+
|
|
9
|
+
### WHY THIS IS HERE ###
|
|
10
|
+
# There is a subset of Summon results that cannot be shown unless a person is
|
|
11
|
+
# on campus or authenticated. So that we can show all results to people
|
|
12
|
+
# searching QuickSearch from on campus we're checking IP addresses. If the IP is a
|
|
13
|
+
# known campus IP we set the s.role=authenticated parameter in the Summon API request.
|
|
14
|
+
|
|
15
|
+
def ip
|
|
16
|
+
request.env['HTTP_X_FORWARDED_FOR'] || request.remote_ip
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def on_campus?(ip)
|
|
20
|
+
ip = remote_ip(ip)
|
|
21
|
+
ip_range_check(ip)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# To spoof ON and OFF campus for development
|
|
25
|
+
def remote_ip(ip)
|
|
26
|
+
if ip == '127.0.0.1'
|
|
27
|
+
'204.84.244.1' #On Campus
|
|
28
|
+
#'127.0.0.1' #Off Campus
|
|
29
|
+
else
|
|
30
|
+
ip
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def ip_range_check(ip)
|
|
35
|
+
QuickSearch::Engine::APP_CONFIG['on_campus'].each do |on_campus_ip_regex|
|
|
36
|
+
if on_campus_ip_regex === ip
|
|
37
|
+
return true
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
return false
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module QuickSearch::QueryFilter
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
include ActionView::Helpers::TextHelper
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
|
|
8
|
+
def filter_query(query)
|
|
9
|
+
if query.match(/ -$/)
|
|
10
|
+
query = query.sub(/ -$/,"")
|
|
11
|
+
end
|
|
12
|
+
query.gsub!('*', ' ')
|
|
13
|
+
query.gsub!('!', ' ')
|
|
14
|
+
query.gsub!('-', ' ') # Solr returns an error if multiple dashes appear at start of query string
|
|
15
|
+
query.gsub!('\\', '')
|
|
16
|
+
# query.gsub!('"', '')
|
|
17
|
+
query.strip!
|
|
18
|
+
query.squish!
|
|
19
|
+
query.downcase! # FIXME: Do we really want to downcase everything?
|
|
20
|
+
query = truncate(query, length: 100, separator: ' ', omission: '', escape: false)
|
|
21
|
+
|
|
22
|
+
query
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module QuickSearch::QueryParser
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def extracted_query(unfiltered_query)
|
|
7
|
+
@unfiltered_query = unfiltered_query
|
|
8
|
+
if extracted_query_and_scope
|
|
9
|
+
query = extracted_query_and_scope[:query]
|
|
10
|
+
else
|
|
11
|
+
query = unfiltered_query
|
|
12
|
+
end
|
|
13
|
+
query
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def extracted_scope(unfiltered_query)
|
|
17
|
+
@unfiltered_query = unfiltered_query
|
|
18
|
+
if extracted_query_and_scope
|
|
19
|
+
scope = extracted_query_and_scope[:value]
|
|
20
|
+
else
|
|
21
|
+
scope = ''
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def extracted_query_and_scope
|
|
26
|
+
if regex_matches = prefix_scope_multi_regex.match(@unfiltered_query)
|
|
27
|
+
regex_matches
|
|
28
|
+
elsif regex_matches = suffix_scope_multi_regex.match(@unfiltered_query)
|
|
29
|
+
regex_matches
|
|
30
|
+
elsif regex_matches = prefix_scope_regex.match(@unfiltered_query)
|
|
31
|
+
regex_matches
|
|
32
|
+
elsif regex_matches = suffix_scope_regex.match(@unfiltered_query)
|
|
33
|
+
regex_matches
|
|
34
|
+
end
|
|
35
|
+
regex_matches
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def prefix_scope_regex
|
|
39
|
+
/^(?<option>scope):(?<value>\S+)\s?(?<query>.*)$/
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def prefix_scope_multi_regex
|
|
43
|
+
/^(?<option>scope):\((?<value>.*?)\)\s?(?<query>.*)$/
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def suffix_scope_regex
|
|
47
|
+
/(?<query>.*)\s(?<option>scope):(?<value>\S+)/
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def suffix_scope_multi_regex
|
|
51
|
+
/^(?<query>.*)\s(?<option>scope):\((?<value>.*)\)$/
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module QuickSearch::SearcherConcern
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
include QuickSearch::OnCampus
|
|
5
|
+
include QuickSearch::QueryParser
|
|
6
|
+
include QuickSearch::EncodeUtf8
|
|
7
|
+
include QuickSearch::SearcherConfig
|
|
8
|
+
require 'benchmark_logger'
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def search_all_in_threads(primary_searcher = 'defaults')
|
|
13
|
+
benchmark "%s server ALL" % CGI.escape(query.to_str) do
|
|
14
|
+
search_threads = []
|
|
15
|
+
@found_types = [] # add the types that are found to a navigation bar
|
|
16
|
+
|
|
17
|
+
primary_searcher_config = ''
|
|
18
|
+
|
|
19
|
+
if primary_searcher == 'defaults'
|
|
20
|
+
searchers = QuickSearch::Engine::APP_CONFIG['searchers']
|
|
21
|
+
else
|
|
22
|
+
searcher_config = searcher_config(primary_searcher)
|
|
23
|
+
if searcher_config and searcher_config.has_key? 'with_paging'
|
|
24
|
+
searchers = searcher_config['with_paging']['searchers']
|
|
25
|
+
else
|
|
26
|
+
searchers = [primary_searcher]
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
searchers.shuffle.each do |search_method|
|
|
31
|
+
search_threads << Thread.new(search_method) do |sm|
|
|
32
|
+
benchmark "%s server #{sm}" % CGI.escape(query.to_str) do
|
|
33
|
+
begin
|
|
34
|
+
klass = "QuickSearch::#{sm.camelize}Searcher".constantize
|
|
35
|
+
http_client = HTTPClient.new
|
|
36
|
+
update_searcher_timeout(http_client, search_method)
|
|
37
|
+
# FIXME: Probably want to set paging and offset somewhere else.
|
|
38
|
+
# searcher = klass.new(http_client, params_q_scrubbed, QuickSearch::Engine::APP_CONFIG['per_page'], 0, 1, on_campus?(request.remote_ip))
|
|
39
|
+
if sm == primary_searcher
|
|
40
|
+
if primary_searcher_config.has_key? 'with_paging'
|
|
41
|
+
per_page = primary_searcher_config['with_paging']['per_page']
|
|
42
|
+
else
|
|
43
|
+
per_page = 10
|
|
44
|
+
end
|
|
45
|
+
searcher = klass.new(http_client, query, per_page, offset(page, per_page), page, on_campus?(ip), scope)
|
|
46
|
+
else
|
|
47
|
+
searcher = klass.new(http_client, query, QuickSearch::Engine::APP_CONFIG['per_page'], 0, 1, on_campus?(ip), scope)
|
|
48
|
+
end
|
|
49
|
+
searcher.search
|
|
50
|
+
unless searcher.is_a? StandardError or searcher.results.blank?
|
|
51
|
+
@found_types.push(sm)
|
|
52
|
+
end
|
|
53
|
+
instance_variable_set "@#{sm}", searcher
|
|
54
|
+
rescue StandardError => e
|
|
55
|
+
# logger.info e
|
|
56
|
+
logger.info "FAILED SEARCH: #{sm} | #{params_q_scrubbed}"
|
|
57
|
+
instance_variable_set :"@#{sm.to_s}", e
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
search_threads.each {|t| t.join}
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def page
|
|
68
|
+
if page_in_params?
|
|
69
|
+
page = params[:page].to_i
|
|
70
|
+
else
|
|
71
|
+
page = 1
|
|
72
|
+
end
|
|
73
|
+
page
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def offset(page, per_page)
|
|
77
|
+
(page * per_page) - per_page
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def query
|
|
81
|
+
extracted_query(params_q_scrubbed)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def scope
|
|
85
|
+
extracted_scope(params_q_scrubbed)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def update_searcher_timeout(client, search_method, xhr=false)
|
|
89
|
+
timeout_type = xhr ? 'xhr_http_timeout' : 'http_timeout'
|
|
90
|
+
timeout = QuickSearch::Engine::APP_CONFIG[timeout_type]
|
|
91
|
+
|
|
92
|
+
if QuickSearch::Engine::APP_CONFIG.has_key? search_method and QuickSearch::Engine::APP_CONFIG[search_method].has_key? timeout_type
|
|
93
|
+
timeout = QuickSearch::Engine::APP_CONFIG[search_method][timeout_type]
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
client.receive_timeout = timeout
|
|
97
|
+
client.send_timeout = timeout
|
|
98
|
+
client.connect_timeout = timeout
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module QuickSearch::SearcherConfig
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
private
|
|
5
|
+
|
|
6
|
+
def searcher_config(searcher)
|
|
7
|
+
# Best Bets searcher is available in QuickSearch core, use app_config
|
|
8
|
+
if searcher == 'best_bets'
|
|
9
|
+
QuickSearch::Engine::APP_CONFIG['best_bets']
|
|
10
|
+
else
|
|
11
|
+
#TODO: test for the existence of this?
|
|
12
|
+
"QuickSearch::Engine::#{searcher.upcase}_CONFIG".constantize
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
end
|