quick_search-core 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -6
- data/app/assets/javascripts/quick_search.js.erb +9 -0
- data/app/assets/javascripts/quick_search/appstats.js.erb +73 -0
- data/app/assets/javascripts/quick_search/appstats_best_bets.js.erb +905 -0
- data/app/assets/javascripts/quick_search/appstats_clicks_overview.js.erb +719 -0
- data/app/assets/javascripts/quick_search/appstats_general_statistics.js.erb +908 -0
- data/app/assets/javascripts/quick_search/appstats_sessions_details.js.erb +660 -0
- data/app/assets/javascripts/quick_search/appstats_sessions_overview.js.erb +481 -0
- data/app/assets/javascripts/quick_search/appstats_spelling_suggestions.js.erb +902 -0
- data/app/assets/javascripts/quick_search/appstats_top_searches.js.erb +633 -0
- data/app/assets/javascripts/quick_search/event_tracking.js.erb +22 -33
- data/app/assets/javascripts/quick_search/xhr_search.js +7 -3
- data/app/assets/stylesheets/quick_search/appstats.scss +148 -0
- data/app/assets/stylesheets/quick_search/quick_search.scss +0 -16
- data/app/controllers/concerns/quick_search/doi_trap.rb +1 -1
- data/app/controllers/quick_search/appstats_controller.rb +267 -144
- data/app/controllers/quick_search/logging_controller.rb +165 -0
- data/app/controllers/quick_search/search_controller.rb +1 -23
- data/app/controllers/quick_search/typeahead_controller.rb +48 -0
- data/app/models/event.rb +6 -0
- data/app/models/search.rb +7 -0
- data/app/models/session.rb +9 -0
- data/app/searchers/quick_search/best_bets_searcher.rb +1 -1
- data/app/views/layouts/quick_search/_google_analytics.html.erb +4 -9
- data/app/views/layouts/quick_search/_search_form.html.erb +2 -2
- data/app/views/layouts/quick_search/application.html.erb +4 -0
- data/app/views/quick_search/appstats/_date_range.html.erb +14 -13
- data/app/views/quick_search/appstats/_graph_best_bets.html.erb +6 -0
- data/app/views/quick_search/appstats/_graph_clicks_overview.html.erb +12 -0
- data/app/views/quick_search/appstats/_graph_general_statistics.html.erb +19 -0
- data/app/views/quick_search/appstats/_graph_sessions_details.html.erb +19 -0
- data/app/views/quick_search/appstats/_graph_sessions_overview.html.erb +9 -0
- data/app/views/quick_search/appstats/_graph_spelling_suggestions.html.erb +6 -0
- data/app/views/quick_search/appstats/_graph_top_searches.html.erb +6 -0
- data/app/views/quick_search/appstats/_menu.html.erb +16 -3
- data/app/views/quick_search/appstats/_sessions_details_device_filters.html.erb +9 -0
- data/app/views/quick_search/appstats/_sessions_details_location_filters.html.erb +9 -0
- data/app/views/quick_search/appstats/_sessions_overview_graph_filters.html.erb +9 -0
- data/app/views/quick_search/appstats/clicks_overview.html.erb +3 -14
- data/app/views/quick_search/appstats/index.html.erb +3 -23
- data/app/views/quick_search/appstats/sessions_details.html.erb +9 -0
- data/app/views/quick_search/appstats/sessions_overview.html.erb +9 -0
- data/app/views/quick_search/appstats/top_searches.html.erb +3 -32
- data/app/views/quick_search/appstats/top_spot.html.erb +7 -7
- data/app/views/quick_search/search/_module_with_paging.html.erb +1 -1
- data/app/views/quick_search/search/_result_title.html.erb +1 -1
- data/config/quicksearch_config.yml.example +3 -0
- data/config/routes.rb +31 -3
- data/db/migrate/20161201141003_create_sessions.rb +12 -0
- data/db/migrate/20161201142811_change_event_columns.rb +11 -0
- data/db/migrate/20161201143901_add_session_id_to_searches.rb +5 -0
- data/db/migrate/20161212192454_add_date_string_columns.rb +11 -0
- data/db/seeds.rb +83 -7
- data/lib/generators/quick_search/templates/quick_search_typeahead.js +253 -0
- data/lib/generators/quick_search/typeahead_generator.rb +162 -0
- data/lib/quick_search/engine.rb +1 -0
- data/lib/quick_search/version.rb +1 -1
- data/test/dummy/db/schema.rb +25 -6
- data/test/dummy/log/benchmark.log +121 -241
- data/test/dummy/log/development.log +236 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/0b/0bXp2nnjPLNuYQRAMo1RkhNr8RSC8vqZo_7soo0XZTE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/3p/3pAfj3gt9c9rLmOrDkMvW2r6Swm5YhuGQ1EN3va9LDE.cache +6 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/3r/3r7qg-LCIcD5882b6GKgRTZycpAlhoSNJccVH06yRCQ.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{UA/UAOIipK_ejTAUFI6XxASoweyUiC3t64VfVzV-MfsFD8.cache → 4h/4hLiHzJdffGLMZCeIkbisOdFQSyqs54YkoZpBpGotVk.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{Hr/Hr-kCuPY72nIKAdnsDTz9JqXd_z1WL6FSGMAq4HppZg.cache → 5Y/5Yh8GnSzywqhuMWMloKnL9FnuIxa9rBw6hN2Ecv0urw.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/8h/8hHsBZ0Il3GVKNj0HgTh-s-XpPVkHrcSY0EJ4v548sk.cache +4 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{fI/fInu_Gja7ik39t207tqj4CtlL0akQRbjD2T7qEtd0zE.cache → 8n/8nKAboU_CeVIX30-Q9BtSV5TXdE07WU8hO0OQ0N3KOs.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{dz/dzCaa80YgyvJINTgsyrVhKv9UQ1OC82GfAsA-IP96iQ.cache → Af/Afug8duevWkZFPkOMnZ5z_IbRT6JMZo4jw1QFmLiXXA.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/C2/C24SLDoUbdiHRmPZx5lIZ3XPXmn9FDq7j7gZmbpDtcE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/CH/CHuDjj47dHGqRD3uN1JNwnlFyjjEKB09KR6WVsLj2Do.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ci/Cif3NOwhu5i6Qm3iRv2gNJLi_cu8yDVz0Nrq8TZu1tc.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/FQ/FQWd8V-Pek1LBAfW9vzcG-FpWySsPRhMVzH9DlPxLWU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Fa/FaYEz8CfLTkxVZvnbgKGvJMhhBwNvEgsZgUwaHNRlaQ.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/IA/IALQq6ICbs3VBSRsaUmGuN73Qv5wDfWTP86VmMh_sVs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/K1/K1jnTrW-_s64kqCA6fnoQ-ID-rDaGX34J-TNPyzDbLs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Mz/MzXE1Go_GKyu6AvJPhw394BtPM_jVTf0hMwobBi15tk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Os/OsIhoBDw5N2AWGQ-EMK79tgwPS1AC6Dy_gMSJdOv2Ss.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{B5/B5ptGSZGmgHvoK2UDCAtpMhWxJEKxKFhyL9ACeBfzQk.cache → PC/PCth9nzoRrp5GI3Ut8FxlGpXjH63V7k2p4PRwfyu2sQ.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Pw/Pw3Jv2p7MsQz6pttCZig6VMVQ30sRyIDRS-2nM32yqY.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/RI/RIOgtcuvLAJZl62RvAzqine3jCO3i2qyhswiW2G1bw8.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/R_/R_6WhfFaPUAOAFfFd4bgUonI5aB4Fa6iOMY2J6G3U98.cache +4 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{pj/pjJDYrBipDo6Tr9_-W4UDzfZZ4UPTy9YpXrBQFRXnlo.cache → S3/S3gPdA-Zqya5r6wNhnlwqGV3B3-GDaA8i1fL_jo66AI.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/SS/SS3eYrFE6ghi5G_3POW760Y4BWo5OAaK5QjDrRGXOcs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{jj/jjdQCKZsewws2eRP7b2AVxRMvseOp8djjlDkB8UOtac.cache → Sq/SqjdxmYsdurpx9xk1ks32WEtf3D9_2BysE7RMxnOlmU.cache} +1 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{os/os0qWv3yDfep0e7vVSGTgfn_n3xc4C4QZgmMzLQn0Ks.cache → Ta/TaJnQ_l0sfSsDOyVoi-S-KZQ6vIwzBhmS6hmNA_n8ug.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{o6/o6ZQbq1aBFuVrE2xLbSbyZH2736sWM3Yj4ky9chT1bI.cache → X_/X_CxFXEdZo2C_in7FopAuAbplHn6W_V0SXyVQAMnTzI.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{sR/sRU-UT8qK_38kkiFDXKBPogO1oOZuSvJFH-pgqPL_Ms.cache → Yh/YhRWll6bzgYE6Dmc5fVKbHyv5om4y3-27UrWeUbQcGk.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{OD/ODHapE0li3WI1laVJoksoI5nmQd-8dDJXq_VxS4XefE.cache → _u/_uiA10I5HyJR94Tbc4a06CzdrQCAXX7Iz86WS5PKDQo.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ai/ainCVF4dxXf85KoOLUSHvMMGg0qBNc7Vg-s-9v2ENJI.cache +4 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/cQ/cQqt0ri9GFvVnIs1pJUugIJs5tDuGQMMntW5CwpK6YY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{1n/1nStVaWIQEwAlksUpB1fInwq6v3TikPvuRaSwwCnCLQ.cache → e0/e0Y2Gz8ftaW2O0RjoN2iWguitI-JQZckScAZqlQYkng.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/iH/iHnlNNY3rfdbVqt8LZBfcDQYONR8dA8LmxA9fv5paro.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{F0/F0oWBwLHpGFYNNtnGav-dJFH8rMDpNA5L8_aWm5Wq34.cache → ir/irxgIDPIY6Wz6fHWYp1dIrqAT1_8oa6-oiwqbFE_e-w.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/kn/knUtyVrg7nMIPldZa4MHhe7cC9eMchLZS4mc5HDWgDY.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ks/ks4DoIuUV6oUzoiXoPh7sW1k5ExNoUkR7ICjwuRnAT0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/m3/m375QQakjXd_2Trpvdot-i90nmeCCh0HWtzS66ZvxUU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/rQ/rQ_FgYkT2hdw9A6XmJKGgVb2dMtCrWWHwtS0X1_kdl0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{pw/pwiIhcWPwTuy5Miz5zqOQGYFx-K3TbaCVQ6ls7EBkk0.cache → rU/rUqFWwHqrT5jeIFCEezOPsMMZiAU7ri6RKBGS2ezAfg.cache} +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/{pO/pO8hHVwybv1ZJBdPa2YC6bjqmk020OYFl85TYxtmrWQ.cache → rq/rqf5-J6k_zLc9ZlUgMj28nviKtRsko3-iEp_m_uNeY0.cache} +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- metadata +143 -119
- data/app/assets/javascripts/quick_search/appstats.js +0 -8
- data/app/views/quick_search/appstats/_click_count_table.html.erb +0 -23
- data/app/views/quick_search/appstats/_top_spot_report_table.html.erb +0 -33
- data/app/views/quick_search/appstats/module_click_detail.html.erb +0 -32
- data/app/views/quick_search/appstats/top_spot_detail.html.erb +0 -35
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/0_/0_w_ydOOEFQOoETxJa-IxKppQocaiDwM5V08djCPYso.cache +0 -3
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/3m/3mWfBeEpm_bJvaPQZYvnnAVtE_2helOWh_Tv-cEflrk.cache +0 -5
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/4s/4sg52OgD5l4qx4GnojCVxg2itqwqb-KRanEdmdMus3Y.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/5U/5UPnsccuZFLk9OqbmFMvB55mbvGptApx9Z55HWjEN90.cache +0 -3
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/9a/9acKNgyVD8_WK401tMy6Ce98g-LS4VpwFvGQdzCV9mI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Ba/BaymviI8cwAJQMOIzWCf6Lt-PM2sNFTvY9hQKsfDNNw.cache +0 -3
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Dd/DdFHg3C_voetfvKGKX7t8PGzZlkO45-huHNtaou5rxg.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Fp/FprCQeeZguht46WNSpA3Y3JHKehovFXrj63nDrvvwFE.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/GJ/GJrfWiarIi0Dt6sdKVMfUF1cdZ6NbqZxXHhzNbFtpBw.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Gp/GpoziOxxB-hisco0rl7Nnsnw0UWud7R9Yge2Q3o1eN4.cache +0 -2
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/It/It5VkJv-53-LICLKZWWyp2WcbD86DGotAL0MY3hhfpg.cache +0 -6
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/O6/O6dw148Xya7NYlsRFMEzJyvRcySM6iOL1jRUpdQo9B8.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Oj/OjMkKTW7OkthjJAQHDID8GV30IZC9F0dJ1zGiFame9U.cache +0 -4
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/SU/SUtZ_ltPqy9A9A-_zqNPhNPvjxCOnrdqXHSZv5S9mOk.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Tv/TvZgmm69VEMHUJQIBoij61oXMkgzp6whVo7l8mJ9qpw.cache +0 -3
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/YJ/YJZdK01T1KTS84Mb6p_2TasmJNZeGZc4FMtBPCKGr_M.cache +0 -3
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ah/ahhhd3ysbQmVDNzq2L_rb4t6rqqdnqeY6ujztBoZDA8.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gv/gvZKkbgiExbcQrT4eo0HB-j4JoDRAxdmDjKRxeEdK0Y.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/hj/hj_r-O1QjHJIPcZVnlB_FGPdIRAi9NkxpT2oXDRIsGE.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/o2/o2V1ahk8vFR6sXWNh5BB7w6MBj04zCyX-o1xFZONydE.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/tE/tEO71oPPFXN_2c4p39nU0OiF9ARg13fjdQlnPqAx1KY.cache +0 -4
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/tW/tWFRsAv4WWu2ch-x3AJZd3KOvBXG3MwH6Q6Xn-tFBtw.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/x6/x6W754ylumshr3wBUHHmcgyWs8UR3Od7FaI6tqvjKmk.cache +0 -1
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/yy/yyJ1P7RQciOiW8TgQiu1RMDdbWd4rqxd2BGU9HkY3L8.cache +0 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
module QuickSearch
|
2
|
+
|
3
|
+
##
|
4
|
+
# This class handles QuickSearch's internal logging of queries, events (clicks & serves), and sessions
|
5
|
+
|
6
|
+
class LoggingController < ApplicationController
|
7
|
+
|
8
|
+
include QuickSearch::OnCampus
|
9
|
+
|
10
|
+
before_action :handle_session
|
11
|
+
protect_from_forgery except: :log_event
|
12
|
+
|
13
|
+
##
|
14
|
+
# Logs a search to the database
|
15
|
+
#
|
16
|
+
# This is an API endpoint for logging a search. It requires that at least a search query and a page are
|
17
|
+
# present in the query parameters. It returns a 200 OK HTTP status if the request was successful, or
|
18
|
+
# an 400 BAD REQUEST HTTP status if any parameters are missing.
|
19
|
+
|
20
|
+
def log_search
|
21
|
+
if params[:query].present? && params[:page].present?
|
22
|
+
@session.searches.create(query: params[:query], page: params[:page])
|
23
|
+
head :ok
|
24
|
+
else
|
25
|
+
head :bad_request
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Logs an event to the database. Typically, these can be clicks or serves.
|
31
|
+
#
|
32
|
+
# This is an API endpoint for logging an event. It requires that at least a TODO are
|
33
|
+
# present in the query parameters. It returns a 200 OK HTTP status if the request was successful, or
|
34
|
+
# an 400 BAD REQUEST HTTP status if any parameters are missing. This endpoint supports JSONP requests.
|
35
|
+
|
36
|
+
def log_event
|
37
|
+
if params[:category].present? && params[:event_action].present? && params[:label].present?
|
38
|
+
# if an action isn't passed in, assume that it is a click
|
39
|
+
action = params.fetch(:action_type, 'click')
|
40
|
+
|
41
|
+
# create a new event on the current session
|
42
|
+
@session.events.create(category: params[:category], item: params[:event_action], query: params[:label][0..250], action: action)
|
43
|
+
|
44
|
+
if params[:ga].present? and params[:ga]
|
45
|
+
send_event_to_ga(params[:category], params[:event_action], params[:label])
|
46
|
+
end
|
47
|
+
|
48
|
+
# check whether this is a jsonp request
|
49
|
+
if params[:callback].present?
|
50
|
+
render :json => { 'response': 'success' }, :callback => params[:callback]
|
51
|
+
else
|
52
|
+
render :json => { 'response': 'success' }
|
53
|
+
end
|
54
|
+
else
|
55
|
+
head :bad_request
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
##
|
63
|
+
# Logs an event to Google Analytics using the Measurement Protocol API
|
64
|
+
# https://developers.google.com/analytics/devguides/collection/protocol/v1/
|
65
|
+
|
66
|
+
def send_event_to_ga(category, action, label)
|
67
|
+
# google_analytics_client_id is a UUID that identifies a particular client to the GA Measurement Protocol API
|
68
|
+
if QuickSearch::Engine::APP_CONFIG['google_analytics_tracking_id'].blank? or QuickSearch::Engine::APP_CONFIG['google_analytics_client_id'].blank?
|
69
|
+
return false
|
70
|
+
end
|
71
|
+
|
72
|
+
# Pass along the client user agent and IP address so it is associated
|
73
|
+
# with the event in Google Analytics
|
74
|
+
params = {
|
75
|
+
v: 1,
|
76
|
+
t: 'event',
|
77
|
+
tid: QuickSearch::Engine::APP_CONFIG['google_analytics_tracking_id'],
|
78
|
+
cid: QuickSearch::Engine::APP_CONFIG['google_analytics_client_id'],
|
79
|
+
ec: category,
|
80
|
+
ea: action,
|
81
|
+
el: label,
|
82
|
+
uip: request.remote_ip,
|
83
|
+
ua: request.user_agent,
|
84
|
+
}
|
85
|
+
|
86
|
+
client = HTTPClient.new
|
87
|
+
url = "https://www.google-analytics.com/collect?" + params.to_query
|
88
|
+
|
89
|
+
# The measurement protocol API does not validate responses.
|
90
|
+
# The best way to test this is testing the query string against:
|
91
|
+
# https://ga-dev-tools.appspot.com/hit-builder/
|
92
|
+
|
93
|
+
client.post(url)
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
##
|
98
|
+
# Handles creating/updating a session on every request
|
99
|
+
|
100
|
+
def handle_session
|
101
|
+
if is_existing_session?
|
102
|
+
update_session
|
103
|
+
else
|
104
|
+
new_session
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
##
|
109
|
+
# Returns true if current request has an existing session, false otherwise
|
110
|
+
|
111
|
+
def is_existing_session?
|
112
|
+
cookies.has_key? :session_id and Session.find_by(session_uuid: cookies[:session_id])
|
113
|
+
end
|
114
|
+
|
115
|
+
##
|
116
|
+
# Returns true if current request was from a mobile device
|
117
|
+
#
|
118
|
+
# Uses User-Agent from request to make the determination, which may not be all-encompassing
|
119
|
+
# but works for most modern devices/browsers (iOS, Android). Looks for the string "Mobi" within
|
120
|
+
# the user-agent, which normally contains either Mobi or Mobile if the request was from a mobile browser
|
121
|
+
|
122
|
+
def is_mobile?
|
123
|
+
# TODO: better test for mobile?
|
124
|
+
# Recommended here as simple test: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
125
|
+
request.user_agent.include? "Mobi"
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Creates a new session, and logs it in the database
|
130
|
+
#
|
131
|
+
# A session is tracked by a UUID that is stored in a cookie, and has a 5 minute expiry time.
|
132
|
+
# Sessions are stored in the database with the time they were initiated, their expiry time (or end time),
|
133
|
+
# whether the request originated from a campus IP address, and whether the request originated from a mobile device
|
134
|
+
|
135
|
+
def new_session
|
136
|
+
on_campus = on_campus?(request.remote_ip)
|
137
|
+
is_mobile = is_mobile?
|
138
|
+
session_expiry = 5.minutes.from_now
|
139
|
+
session_uuid = SecureRandom.uuid
|
140
|
+
|
141
|
+
# create session in db
|
142
|
+
@session = Session.create(session_uuid: session_uuid, expiry: session_expiry, on_campus: on_campus, is_mobile: is_mobile)
|
143
|
+
# set cookie
|
144
|
+
cookies[:session_id] = { :value => session_uuid, :expires => session_expiry }
|
145
|
+
end
|
146
|
+
|
147
|
+
##
|
148
|
+
# Updates a session's expiration time on cookie and in database
|
149
|
+
#
|
150
|
+
# When a request is made with a non-expired session, the expiration time is updated to 5 minutes from the current time.
|
151
|
+
# This update is reflected in the cookie as well as in the database entry for the session.
|
152
|
+
|
153
|
+
def update_session
|
154
|
+
# update session expiry in the database
|
155
|
+
session_id = cookies[:session_id]
|
156
|
+
@session = Session.find_by session_uuid: session_id
|
157
|
+
@session.expiry = 5.minutes.from_now
|
158
|
+
@session.save
|
159
|
+
|
160
|
+
# update session expiry on cookie
|
161
|
+
cookies[:session_id] = { :value => session_id, :expires => @session.expiry }
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
end
|
@@ -12,7 +12,6 @@ module QuickSearch
|
|
12
12
|
|
13
13
|
before_action :doi_trap, :log_query
|
14
14
|
after_action :realtime_message, only: [:index]
|
15
|
-
protect_from_forgery except: :log_event
|
16
15
|
|
17
16
|
def index
|
18
17
|
loaded_searches
|
@@ -114,28 +113,6 @@ module QuickSearch
|
|
114
113
|
end
|
115
114
|
end
|
116
115
|
|
117
|
-
def log_search
|
118
|
-
if params[:query].present? && params[:page].present?
|
119
|
-
Search.create(query: params[:query], page: params[:page])
|
120
|
-
head :ok
|
121
|
-
else
|
122
|
-
head :bad_request
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
def log_event
|
127
|
-
if params[:category].present? && params[:event_action].present? && params[:label].present?
|
128
|
-
Event.create(category: params[:category], action: params[:event_action], label: params[:label][0..250])
|
129
|
-
if params[:callback].present?
|
130
|
-
head :ok, content_type: 'text/javascript'
|
131
|
-
else
|
132
|
-
head :ok
|
133
|
-
end
|
134
|
-
else
|
135
|
-
head :bad_request
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
116
|
private
|
140
117
|
|
141
118
|
def http_search(endpoint = 'defaults', page_to_render = :index)
|
@@ -238,6 +215,7 @@ module QuickSearch
|
|
238
215
|
result
|
239
216
|
end
|
240
217
|
|
218
|
+
# TODO: move this --- is this necessary?
|
241
219
|
def log_query
|
242
220
|
if search_in_params?
|
243
221
|
@log_query = filter_query(params_q_scrubbed)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module QuickSearch
|
2
|
+
class TypeaheadController < ApplicationController
|
3
|
+
protect_from_forgery except: :typeahead
|
4
|
+
|
5
|
+
# This method should return a list of search suggestions for a given searcher
|
6
|
+
# It should return errors if there is no param called 'searcher', if the searcher does not exist
|
7
|
+
# or if the searcher doesn't implement the 'typeahead' method
|
8
|
+
# Otherwise, it should return the result of calling the 'typeahead' method as JSON
|
9
|
+
|
10
|
+
def typeahead
|
11
|
+
# :searcher param expected to be name of a searcher with underscores, ie: ematrix_journal
|
12
|
+
searcher = params[:searcher]
|
13
|
+
query = params[:q] or ''
|
14
|
+
total = params[:total] or 3
|
15
|
+
|
16
|
+
if searcher.blank?
|
17
|
+
logger.error "Typeahead request: no searcher param provided"
|
18
|
+
head :bad_request
|
19
|
+
return nil
|
20
|
+
end
|
21
|
+
|
22
|
+
searcher_string = "QuickSearch::#{searcher.camelize}Searcher"
|
23
|
+
|
24
|
+
begin
|
25
|
+
klass = searcher_string.constantize
|
26
|
+
rescue NameError
|
27
|
+
logger.error "Typeahead request: searcher #{searcher} does not exist"
|
28
|
+
head :bad_request
|
29
|
+
return nil
|
30
|
+
end
|
31
|
+
|
32
|
+
if klass.method_defined? :typeahead
|
33
|
+
typeahead_result = klass.new(HTTPClient.new, query, total).typeahead
|
34
|
+
|
35
|
+
if params.has_key? 'callback'
|
36
|
+
render json: typeahead_result, callback: params['callback']
|
37
|
+
else
|
38
|
+
render json: typeahead_result
|
39
|
+
end
|
40
|
+
else
|
41
|
+
logger.error "Typeahead request: searcher #{searcher} has no typeahead method"
|
42
|
+
head :bad_request
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
data/app/models/event.rb
CHANGED
data/app/models/search.rb
CHANGED
@@ -1,15 +1,10 @@
|
|
1
1
|
<% if Rails.env == 'production' or Rails.env == 'staging' %>
|
2
2
|
<script>
|
3
|
-
|
4
|
-
|
5
|
-
_gaq.push(['_setAccount', "<%= QuickSearch::Engine::APP_CONFIG['google_analytics_tracking_id'] %>"]);
|
6
|
-
_gaq.push(['_trackPageview']);
|
3
|
+
// Universal analytics
|
4
|
+
(function(i,s,o,g,r,a,m){i["GoogleAnalyticsObject"]=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,"script","//www.google-analytics.com/analytics.js","ga");
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
11
|
-
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
12
|
-
})();
|
6
|
+
ga("create", "<%= QuickSearch::Engine::APP_CONFIG['google_analytics_tracking_id'] %>", "auto");
|
7
|
+
ga("send", "pageview");
|
13
8
|
|
14
9
|
</script>
|
15
10
|
<% end %>
|
@@ -4,9 +4,9 @@
|
|
4
4
|
<div class="row collapse">
|
5
5
|
<div class="small-10 columns">
|
6
6
|
<% if @query %>
|
7
|
-
<input type="search" name="q" id="params-q" class="
|
7
|
+
<input type="search" name="q" id="params-q" class="search-query" value="<%= @query %>" />
|
8
8
|
<% else %>
|
9
|
-
<input type="search" name="q" id="params-q" class="
|
9
|
+
<input type="search" name="q" id="params-q" class="search-query" placeholder="<%= @search_form_placeholder %>" />
|
10
10
|
<% end %>
|
11
11
|
</div>
|
12
12
|
<div class="small-2 columns">
|
@@ -12,6 +12,10 @@
|
|
12
12
|
<%= javascript_include_tag 'application' %>
|
13
13
|
<%= render '/layouts/quick_search/head' %>
|
14
14
|
<%= render '/layouts/quick_search/google_analytics' %>
|
15
|
+
|
16
|
+
<!-- datepicker (temp) -->
|
17
|
+
<link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
18
|
+
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
|
15
19
|
</head>
|
16
20
|
<body class="<%= body_class %>" data-quicksearch-ga-query="<%= strip_tags(@log_query) %>">
|
17
21
|
<div class="off-canvas-wrap">
|
@@ -1,15 +1,16 @@
|
|
1
1
|
<% title('Foo') %>
|
2
|
-
<div class="
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
</
|
12
|
-
|
13
|
-
|
14
|
-
</
|
2
|
+
<div class="medium-2 columns" style="position: fixed; right: 0;">
|
3
|
+
<div style="">
|
4
|
+
<label for="from" class="inputLabel"> From: </label>
|
5
|
+
<input id="from" type="text" name="from">
|
6
|
+
<label for="to" class="inputLabel"> To: </label>
|
7
|
+
<input id="to" type="text" name="to">
|
8
|
+
<p id="datePickerText"> Days in Sample: </p>
|
9
|
+
<p id="numDays"><%= "#{@days_in_sample}" %></p>
|
10
|
+
<% if @page_title=='spelling-suggestion'||@page_title=='best-bets-regular'||@page_title=='Top Searches' %>
|
11
|
+
<label for="num" class="inputLabel"> # Results: </label>
|
12
|
+
<input id="num" type="number" name="num" min="0" max="200">
|
13
|
+
<% end %>
|
14
|
+
<button id="dateButton" type="button"> Update </button>
|
15
|
+
<div>
|
15
16
|
</div>
|
@@ -0,0 +1,12 @@
|
|
1
|
+
<h1><%= @page_title %></h1>
|
2
|
+
<h2>Frequency of Modules Clicked</h2>
|
3
|
+
<div class="graphGroup">
|
4
|
+
<div class="iconContainer" id="moduleIconContainer"></div>
|
5
|
+
<svg id="graph_module_clicks" width="840" height="240"></svg>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<h2>Frequency of Result-Type Guides Clicked</h2>
|
9
|
+
<div class="graphGroup">
|
10
|
+
<div class="iconContainer" id="resultIconContainer"></div>
|
11
|
+
<svg id="graph_result_clicks" width="840" height="240"></svg>
|
12
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h1><%= @page_title %></h1>
|
2
|
+
<div class="graphGroup">
|
3
|
+
<div class="iconContainer" id="tableIconContainer"></div>
|
4
|
+
<svg class="graph" id="graph_general_table" width="840" height="473"></svg>
|
5
|
+
</svg>
|
6
|
+
</div>
|
7
|
+
|
8
|
+
<div class="graphGroup">
|
9
|
+
<div class="iconContainer" id="graphIconContainer"></div>
|
10
|
+
<svg class="graph" id="graph_general_statistics" width="840" height="473">
|
11
|
+
</svg>
|
12
|
+
</div>
|
13
|
+
|
14
|
+
<div style="display: inline-block; width: 1000px;">
|
15
|
+
<svg class="graph_mini" id="mini0" width="280" height="158" onmouseover="lighten()" onmouseout="darken()"></svg>
|
16
|
+
<svg class="graph_mini" id="mini1" width="280" height="158" onmouseover="lighten()" onmouseout="darken()"></svg>
|
17
|
+
<svg class="graph_mini" id="mini2" width="280" height="158" onmouseover="lighten()" onmouseout="darken()"></svg>
|
18
|
+
<div class="clearfix"></div>
|
19
|
+
</div>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<h1><%= @page_title %></h1>
|
2
|
+
<h2> Sessions by Location </h2>
|
3
|
+
<div class="graphGroup">
|
4
|
+
<div class="iconContainer" id="locationIconContainer"></div>
|
5
|
+
<div style="float: left; display: inline-block;">
|
6
|
+
<svg id="graph_sessions_location" width="840" height="473"></svg>
|
7
|
+
</div>
|
8
|
+
<%= render partial: 'sessions_details_location_filters' %>
|
9
|
+
</div>
|
10
|
+
|
11
|
+
<div class="clearfix"></div>
|
12
|
+
<h2> Sessions by Access Device </h2>
|
13
|
+
<div class="graphGroup">
|
14
|
+
<div class="iconContainer" id="deviceIconContainer"></div>
|
15
|
+
<div style="float: left; display: inline-block;">
|
16
|
+
<svg id="graph_sessions_device" width="840" height="473"></svg>
|
17
|
+
</div>
|
18
|
+
<%= render partial: 'sessions_details_device_filters' %>
|
19
|
+
</div>
|
@@ -0,0 +1,9 @@
|
|
1
|
+
<h1><%= @page_title %></h1>
|
2
|
+
<h2>Sessions Overview</h2>
|
3
|
+
<div class="graphGroup">
|
4
|
+
<div class="iconContainer" id="sessIconContainer"></div>
|
5
|
+
<div style="float: left; display: inline-block;">
|
6
|
+
<svg id="graph_sessions_overview" width="840" height="473"></svg>
|
7
|
+
</div>
|
8
|
+
<%= render partial: 'sessions_overview_graph_filters' %>
|
9
|
+
</div>
|