From 0e63c14613c1b8b02ea74d1468e3999e6d637b23 Mon Sep 17 00:00:00 2001 From: jvelilla Date: Tue, 13 Oct 2015 10:23:30 -0300 Subject: [PATCH] Added Module Custom Search Added Google custom search library Added HTTP client extension libaray Updated demo example to use the Module Custom Search --- examples/demo/demo-safe.ecf | 2 + .../custom_search/config/custom_search.json | 6 + .../custom_search/templates/block_search.tpl | 40 +++ examples/demo/site/themes/bootstrap/page.tpl | 11 + examples/demo/src/ewf_roc_server_execution.e | 3 + library/gcse/Readme.md | 4 + library/gcse/gcse-safe.ecf | 21 ++ library/gcse/gcse.ecf | 28 ++ library/gcse/license.lic | 10 + library/gcse/src/gcse_api.e | 243 ++++++++++++++++++ library/gcse/src/gcse_page.e | 113 ++++++++ library/gcse/src/gcse_page_item.e | 220 ++++++++++++++++ library/gcse/src/gcse_page_map.e | 38 +++ library/gcse/src/gcse_query_parameters.e | 237 +++++++++++++++++ library/gcse/src/gcse_response.e | 88 +++++++ library/gcse/test/application.e | 80 ++++++ library/gcse/test/gcse_api_test_set.e | 31 +++ library/gcse/test/test.ecf | 21 ++ .../http_client_extension-safe.ecf | 26 ++ .../http_client_extension.ecf | 25 ++ .../src/request/request.e | 199 ++++++++++++++ .../src/request/request_executor.e | 97 +++++++ .../src/response/response.e | 57 ++++ .../src/util/http_client_helper.e | 99 +++++++ modules/auth/cms_authentication_module.e | 1 + modules/custom_search/Readme.md | 1 + modules/custom_search/custom_search.ecf | 18 ++ .../site/config/custom_search.json | 6 + .../site/templates/block_search.tpl | 40 +++ .../src/google_custom_search_module.e | 154 +++++++++++ 30 files changed, 1919 insertions(+) create mode 100644 examples/demo/site/modules/custom_search/config/custom_search.json create mode 100644 examples/demo/site/modules/custom_search/templates/block_search.tpl create mode 100644 library/gcse/Readme.md create mode 100644 library/gcse/gcse-safe.ecf create mode 100644 library/gcse/gcse.ecf create mode 100644 library/gcse/license.lic create mode 100644 library/gcse/src/gcse_api.e create mode 100644 library/gcse/src/gcse_page.e create mode 100644 library/gcse/src/gcse_page_item.e create mode 100644 library/gcse/src/gcse_page_map.e create mode 100644 library/gcse/src/gcse_query_parameters.e create mode 100644 library/gcse/src/gcse_response.e create mode 100644 library/gcse/test/application.e create mode 100644 library/gcse/test/gcse_api_test_set.e create mode 100644 library/gcse/test/test.ecf create mode 100644 library/http_client_extension/http_client_extension-safe.ecf create mode 100644 library/http_client_extension/http_client_extension.ecf create mode 100644 library/http_client_extension/src/request/request.e create mode 100644 library/http_client_extension/src/request/request_executor.e create mode 100644 library/http_client_extension/src/response/response.e create mode 100644 library/http_client_extension/src/util/http_client_helper.e create mode 100644 modules/custom_search/Readme.md create mode 100644 modules/custom_search/custom_search.ecf create mode 100644 modules/custom_search/site/config/custom_search.json create mode 100644 modules/custom_search/site/templates/block_search.tpl create mode 100644 modules/custom_search/src/google_custom_search_module.e diff --git a/examples/demo/demo-safe.ecf b/examples/demo/demo-safe.ecf index 8f28c4b..2f8ffc1 100644 --- a/examples/demo/demo-safe.ecf +++ b/examples/demo/demo-safe.ecf @@ -26,6 +26,8 @@ + + +
    + + + {foreach from="$result.items" item="item"} +
  1. + +
  2. + {/foreach} + + +
+ + \ No newline at end of file diff --git a/examples/demo/site/themes/bootstrap/page.tpl b/examples/demo/site/themes/bootstrap/page.tpl index 31474dc..aba3059 100644 --- a/examples/demo/site/themes/bootstrap/page.tpl +++ b/examples/demo/site/themes/bootstrap/page.tpl @@ -37,6 +37,17 @@ {/if} + +
+
+
+
+ + +
+
+
+
diff --git a/examples/demo/src/ewf_roc_server_execution.e b/examples/demo/src/ewf_roc_server_execution.e index db4dbf7..d6017f8 100644 --- a/examples/demo/src/ewf_roc_server_execution.e +++ b/examples/demo/src/ewf_roc_server_execution.e @@ -92,6 +92,9 @@ feature -- CMS setup create {CMS_DEMO_MODULE} m.make a_setup.register_module (m) + + create {GOOGLE_CUSTOM_SEARCH_MODULE} m.make + a_setup.register_module (m) end end diff --git a/library/gcse/Readme.md b/library/gcse/Readme.md new file mode 100644 index 0000000..dc80b1f --- /dev/null +++ b/library/gcse/Readme.md @@ -0,0 +1,4 @@ +Google Custom Search Engine Eiffel Lbrary + +Based on https://developers.google.com/custom-search/json-api/v1/using_rest + diff --git a/library/gcse/gcse-safe.ecf b/library/gcse/gcse-safe.ecf new file mode 100644 index 0000000..235412e --- /dev/null +++ b/library/gcse/gcse-safe.ecf @@ -0,0 +1,21 @@ + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + diff --git a/library/gcse/gcse.ecf b/library/gcse/gcse.ecf new file mode 100644 index 0000000..a086fb8 --- /dev/null +++ b/library/gcse/gcse.ecf @@ -0,0 +1,28 @@ + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + + + + + diff --git a/library/gcse/license.lic b/library/gcse/license.lic new file mode 100644 index 0000000..93c113a --- /dev/null +++ b/library/gcse/license.lic @@ -0,0 +1,10 @@ +${NOTE_KEYWORD} + copyright: "2011-${YEAR} Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" diff --git a/library/gcse/src/gcse_api.e b/library/gcse/src/gcse_api.e new file mode 100644 index 0000000..5a46f82 --- /dev/null +++ b/library/gcse/src/gcse_api.e @@ -0,0 +1,243 @@ +note + description: "[ + Simple API to call Google Custome Search Engine + Example call: + GET https://www.googleapis.com/customsearch/v1?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures + ]" + date: "$Date: 2015-10-09 08:11:07 -0300 (vi., 09 oct. 2015) $" + revision: "$Revision: 97973 $" + EIS: "name=Google Custom Search Engine", "src=https://developers.google.com/custom-search/json-api/v1/using_rest", "protocol=uri" + +class + GCSE_API + +create + make + +feature {NONE} -- Initialization + + make (a_query_parameters: GCSE_QUERY_PARAMETERS) + -- Create an object GCSE with query_parameters `a_query_parameters' + do + query_paremeter := a_query_parameters + ensure + query_parameters_set: query_paremeter = a_query_parameters + end + +feature -- Access + + base_uri: STRING_8 = "https://www.googleapis.com/customsearch/v1" + -- Google custom search base URI + + query_paremeter: GCSE_QUERY_PARAMETERS + -- Google custom search parameters. + + last_result: detachable GCSE_RESPONSE + -- Search results. + +feature -- Status Reports + + errors: detachable LIST [READABLE_STRING_8] + -- optional table of error codes + +feature -- API + + search + -- Search + local + l_parser: JSON_PARSER + l_gcse_response: detachable GCSE_RESPONSE + do + -- Data format for the response. + -- At the moment we are using the default value: json + -- but it's possible to define atom response using the alt parameter. + last_result := Void + if attached get as l_response then + if attached l_response.body as l_body then + create l_parser.make_with_string (l_body) + l_parser.parse_content + if l_parser.is_parsed and then attached {JSON_OBJECT} l_parser.parsed_json_object as jv then + -- Queries + create l_gcse_response + if attached {JSON_OBJECT} jv.item (queries_key) as jqueries then + -- Next Page + if attached {GCSE_PAGE} query_page (next_page_key, jqueries) as l_page then + l_gcse_response.set_next_page (l_page) + end + -- Current Page + if attached {GCSE_PAGE} query_page (request_key, jqueries) as l_page then + l_gcse_response.set_current_page (l_page) + end + -- Previous Page + if attached {GCSE_PAGE} query_page (previous_page_key, jqueries) as l_page then + l_gcse_response.set_previous_page (l_page) + end + end + if attached {JSON_ARRAY} jv.item (items_key) as jitems then + across jitems as ic loop + if attached{JSON_OBJECT} ic.item as j_item then + l_gcse_response.add_item (item (j_item)) + end + end + end + + end + else + put_error (l_response.status.out) + end + else + put_error ("unknown") + end + last_result := l_gcse_response + end + +feature {NONE} -- REST API + + get: detachable RESPONSE + -- Reading Data. + local + l_request: REQUEST + do + create l_request.make ("GET", new_uri) + Result := l_request.execute + end + +feature {NONE} -- Implementation + + new_uri: STRING_8 + -- new uri (BaseUri?key=secret_value&cx=a_cx_id&q=a_query + -- ?key=INSERT_YOUR_API_KEY&cx=017576662512468239146:omuauf_lfve&q=lectures + -- full teamplte BaseUri?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}& + -- safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}& + -- googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}& + -- siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}& + -- orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}& + -- searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}& + -- imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json" + + do + create Result.make_from_string (base_uri) + Result.append ("?key=") + Result.append (query_paremeter.secret) + Result.append ("&cx=") + Result.append (query_paremeter.cx) + Result.append ("&q=") + Result.append (query_paremeter.query) + -- num + if attached query_paremeter.num as l_num then + Result.append ("&num=") + Result.append (l_num) + end + if attached query_paremeter.start as l_start then + Result.append ("&start=") + Result.append (l_start) + end + end + + put_error (a_code: READABLE_STRING_GENERAL) + -- put error with code `a_code'. + local + l_errors: like errors + utf: UTF_CONVERTER + do + l_errors := errors + if l_errors = Void then + create {ARRAYED_LIST [STRING]} l_errors.make (1) + errors := l_errors + end + l_errors.force (utf.utf_32_string_to_utf_8_string_8 (a_code)) + end + + item (a_item: JSON_OBJECT): GCSE_PAGE_ITEM + -- Google Result Metadata Item. + do + create Result + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("kind")) as l_kind then + Result.set_kind (l_kind.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("title")) as l_title then + Result.set_title (l_title.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("htmlTitle")) as l_htmltitle then + Result.set_html_title (l_htmltitle.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("link")) as l_link then + Result.set_link (l_link.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("displayLink")) as l_display_link then + Result.set_display_link (l_display_link.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("snippet")) as l_snippet then + Result.set_snippet (l_snippet.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("htmlSnippet")) as l_html_snippet then + Result.set_html_snippet (l_html_snippet.item) + end + if attached {JSON_STRING} a_item.item (create {JSON_STRING}.make_from_string ("formattedUrl")) as l_formatted_url then + Result.set_formatted_url (l_formatted_url.item) + end + end + + query_page (a_page_key: JSON_STRING; a_queries: JSON_OBJECT): detachable GCSE_PAGE + -- Google result medata query. Return a query page based for a query with page key `a_page_key', if any. + do + if attached {JSON_ARRAY} a_queries.item (a_page_key) as jquerypage and then attached {JSON_OBJECT} jquerypage.i_th (1) as jpage then + create Result + if attached {JSON_STRING} jpage.item (create {JSON_STRING}.make_from_string ("title")) as l_title then + Result.set_title (l_title.item) + end + if attached {JSON_STRING} jpage.item (create {JSON_STRING}.make_from_string ("totalResults")) as l_results then + Result.set_total_results (l_results.item.to_integer) + end + if attached {JSON_STRING} jpage.item (create {JSON_STRING}.make_from_string ("searchTerms")) as l_search_terms then + Result.set_search_terms (l_search_terms.item) + end + -- TODO check if we should use INTEGER_64 + if attached {JSON_NUMBER} jpage.item (create {JSON_STRING}.make_from_string ("count")) as l_count then + Result.set_count (l_count.integer_64_item.as_integer_32) + end + if attached {JSON_NUMBER} jpage.item (create {JSON_STRING}.make_from_string ("startIndex")) as l_index then + Result.set_start_index (l_index.integer_64_item.as_integer_32) + end + end + end + +feature {NONE} -- JSON Keys + + queries_key: JSON_STRING + do + create Result.make_from_string ("queries") + end + + next_page_key: JSON_STRING + do + create Result.make_from_string ("nextPage") + end + + request_key: JSON_STRING + do + create Result.make_from_string ("request") + end + + previous_page_key: JSON_STRING + do + create Result.make_from_string ("previousPage") + end + + items_key: JSON_STRING + do + create Result.make_from_string ("items") + end + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/gcse/src/gcse_page.e b/library/gcse/src/gcse_page.e new file mode 100644 index 0000000..9fc2cae --- /dev/null +++ b/library/gcse/src/gcse_page.e @@ -0,0 +1,113 @@ +note + description: "Represent metadata describing the query for the current set of results." + date: "$Date: 2015-10-09 08:11:07 -0300 (vi., 09 oct. 2015) $" + revision: "$Revision: 97973 $" + +class + GCSE_PAGE + +feature -- Access + + search_terms: detachable STRING_8 + -- search term + + title: detachable STRING_8 + -- Search title. + + total_results: INTEGER + -- Search total results. + + count: INTEGER + -- Rows per page. + + start_index: INTEGER + -- Page index. + +feature -- Element change + + set_search_terms (a_search_terms: like search_terms) + -- Assign `search_terms' with `a_search_terms'. + do + search_terms := a_search_terms + ensure + search_terms_assigned: search_terms = a_search_terms + end + +feature -- Change element + + set_title (a_title: like title) + -- Set title with `a_title' + do + title := a_title + ensure + title_set: title = a_title + end + + set_total_results (a_total_results: like total_results) + -- Set total_results with `a_total_results'. + do + total_results := a_total_results + ensure + total_results_set: total_results = a_total_results + end + + set_count (a_count: like count) + -- Set count with `a_count'. + do + count := a_count + ensure + count_set: count = a_count + end + + set_start_index (a_start_index: like start_index) + -- Set start_index with `a_start_index'. + do + start_index := a_start_index + ensure + start_index_set: start_index = a_start_index + end + +feature -- Output + + to_string: STRING_8 + do + create Result.make_from_string ("%NPage details%N") + if attached title as l_title then + Result.append ("Title:") + Result.append (l_title) + Result.append_character ('%N') + end + if attached search_terms as l_search_tearm then + Result.append ("Search Tearm:") + Result.append (l_search_tearm) + Result.append_character ('%N') + end + + Result.append ("Count:") + Result.append (count.out) + Result.append_character ('%N') + Result.append ("Total Result:") + Result.append (count.out) + Result.append_character ('%N') + Result.append ("Count:") + Result.append (total_results.out) + Result.append_character ('%N') + Result.append ("Start index:") + Result.append (start_index.out) + Result.append_character ('%N') + + end + + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/gcse/src/gcse_page_item.e b/library/gcse/src/gcse_page_item.e new file mode 100644 index 0000000..469bacc --- /dev/null +++ b/library/gcse/src/gcse_page_item.e @@ -0,0 +1,220 @@ +note + description: "Represent a search result, include the URL, title and text snippets that describe the result" + date: "$Date: 2015-10-09 08:11:07 -0300 (vi., 09 oct. 2015) $" + revision: "$Revision: 97973 $" + +class + GCSE_PAGE_ITEM + +inherit + + SHARED_HTML_ENCODER + +feature -- Access + + html_formatted_url: detachable STRING_8 + -- Html formatted url of this result + + formatted_url: detachable STRING_8 + -- Formatted url of this result + + cache_id: detachable STRING_8 + -- Cache id of this result + + html_snippet: detachable STRING_8 + -- Html snippet of this request + + snippet: detachable STRING_8 + -- Snippet of this result + + snippet_2: detachable STRING_8 + -- Snippet of this result + + display_link: detachable STRING_8 + -- Display link of this result + + link: detachable STRING_8 + -- link of this result + + html_title: detachable STRING_8 + -- html title of result + + title: detachable STRING_8 + -- title of result. + + kind: detachable STRING_8 + -- Kind of actual search result. + + page_map: detachable GCSE_PAGE_MAP + -- Page map + --! Not supported for now. + +feature -- Element change + + set_html_formatted_url (a_html_formatted_url: like html_formatted_url) + -- Assign `html_formatted_url' with `a_html_formatted_url'. + do + html_formatted_url := a_html_formatted_url + ensure + html_formatted_url_assigned: html_formatted_url = a_html_formatted_url + end + + set_formatted_url (a_formatted_url: like formatted_url) + -- Assign `formatted_url' with `a_formatted_url'. + do + formatted_url := a_formatted_url + ensure + formatted_url_assigned: formatted_url = a_formatted_url + end + + set_cache_id (a_cache_id: like cache_id) + -- Assign `cache_id' with `a_cache_id'. + do + cache_id := a_cache_id + ensure + cache_id_assigned: cache_id = a_cache_id + end + + set_html_snippet (a_html_snippet: like html_snippet) + -- Assign `html_snippet' with `a_html_snippet'. + do + html_snippet := a_html_snippet + snippet_2 := html_encoded (a_html_snippet) + ensure + html_snippet_assigned: html_snippet = a_html_snippet + end + + set_snippet (a_snippet: like snippet) + -- Assign `snippet' with `a_snippet'. + do + snippet := a_snippet + ensure + snippet_assigned: snippet = a_snippet + end + + set_display_link (a_display_link: like display_link) + -- Assign `display_link' with `a_display_link'. + do + display_link := a_display_link + ensure + display_link_assigned: display_link = a_display_link + end + + set_link (a_link: like link) + -- Assign `link' with `a_link'. + do + link := a_link + ensure + link_assigned: link = a_link + end + + set_html_title (a_html_title: like html_title) + -- Assign `html_title' with `a_html_title'. + do + html_title := a_html_title + ensure + html_title_assigned: html_title = a_html_title + end + + set_title (a_title: like title) + -- Assign `title' with `a_title'. + do + title := a_title + ensure + title_assigned: title = a_title + end + + set_kind (a_kind: like kind) + -- Assign `kind' with `a_kind'. + do + kind := a_kind + ensure + kind_assigned: kind = a_kind + end + + set_page_map (a_map: like page_map) + -- Assign `kind' with `a_kind'. + do + page_map := a_map + ensure + page_map_assigned: page_map = a_map + end + + +feature -- Output + + to_string: STRING_8 + do + create Result.make_from_string ("%NPage Item details%N") + if attached title as l_title then + Result.append ("Title:") + Result.append (l_title) + Result.append_character ('%N') + end + if attached kind as l_kind then + Result.append ("Kind:") + Result.append (l_kind) + Result.append_character ('%N') + end + if attached html_title as l_html_title then + Result.append ("Html title:") + Result.append (l_html_title) + Result.append_character ('%N') + end + if attached link as l_link then + Result.append ("Link:") + Result.append (l_link) + Result.append_character ('%N') + end + if attached display_link as l_display_link then + Result.append ("Display link:") + Result.append (l_display_link) + Result.append_character ('%N') + end + if attached snippet as l_snippet then + Result.append ("Snippet:") + Result.append (l_snippet) + Result.append_character ('%N') + end + if attached html_snippet as l_html_snippet then + Result.append ("Html snippet:") + Result.append (l_html_snippet) + Result.append_character ('%N') + end + if attached cache_id as l_cache_id then + Result.append ("Cache_id:") + Result.append (l_cache_id) + Result.append_character ('%N') + end + if attached formatted_url as l_formatted_url then + Result.append ("Formatted url:") + Result.append (l_formatted_url) + Result.append_character ('%N') + end + if attached html_formatted_url as l_html_formatted_url then + Result.append ("Html formatted url:") + Result.append (l_html_formatted_url) + Result.append_character ('%N') + end + + end + + html_encoded (s: detachable READABLE_STRING_GENERAL): STRING_8 + do + if s /= Void then + Result := html_encoder.general_encoded_string (s) + else + create Result.make_empty + end + end +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/gcse/src/gcse_page_map.e b/library/gcse/src/gcse_page_map.e new file mode 100644 index 0000000..67468ab --- /dev/null +++ b/library/gcse/src/gcse_page_map.e @@ -0,0 +1,38 @@ +note + description: "Represent a google page map" + date: "$Date: 2015-10-09 08:11:07 -0300 (vi., 09 oct. 2015) $" + revision: "$Revision: 97973 $" + EIS: "name=PageMaps", "src=https://developers.google.com/custom-search/docs/structured_data#pagemaps", "protocol=url" + +class + GCSE_PAGE_MAP + +feature -- Access + +-- "pagemap": { +-- "cse_image": [ +-- { +-- "src": "https://www.eiffel.org/portal/files/userpictures/picture-40.jpg" +-- } +-- ], +-- "cse_thumbnail": [ +-- { +-- "width": "81", +-- "height": "61", +-- "src": "https://encrypted-tbn2.gstatic.com/images?q=tbn:ANd9GcRnC-RKzps6BFItx_MLYBVskFI7U6u0y3VJBInomPYEF5sO6gkip94mLw" +-- } +-- ] +-- } + + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/gcse/src/gcse_query_parameters.e b/library/gcse/src/gcse_query_parameters.e new file mode 100644 index 0000000..77e91e1 --- /dev/null +++ b/library/gcse/src/gcse_query_parameters.e @@ -0,0 +1,237 @@ +note + description: "[ + Represent google custom search parameters + Example url template + "template": "https://www.googleapis.com/customsearch/v1?q={searchTerms}&num={count?}&start={startIndex?}&lr={language?}&safe={safe?}&cx={cx?}&cref={cref?}&sort={sort?}&filter={filter?}&gl={gl?}&cr={cr?}&googlehost={googleHost?}&c2coff={disableCnTwTranslation?}&hq={hq?}&hl={hl?}&siteSearch={siteSearch?}&siteSearchFilter={siteSearchFilter?}&exactTerms={exactTerms?}&excludeTerms={excludeTerms?}&linkSite={linkSite?}&orTerms={orTerms?}&relatedSite={relatedSite?}&dateRestrict={dateRestrict?}&lowRange={lowRange?}&highRange={highRange?}&searchType={searchType}&fileType={fileType?}&rights={rights?}&imgSize={imgSize?}&imgType={imgType?}&imgColorType={imgColorType?}&imgDominantColor={imgDominantColor?}&alt=json" + ]" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + EIS: "GCSE parameters", "src=https://developers.google.com/custom-search/json-api/v1/reference/cse/list", "protocol=URI" + +class + GCSE_QUERY_PARAMETERS + +create + make + +feature {NONE} -- Initialization + + make (a_secret_key, a_cx, a_query: READABLE_STRING_8) + -- Create an object GCSE_QUERY_PARAMETERS with secret key `a_secret_key' and a custom search engine id `a_cx'. + -- and query `a_query'. + do + -- TODO + -- At the moment the API only use cx as Google Custom Search id. + -- Custom search engine ID - Use either cx or cref to specify the custom search engine you want to use to perform this search + + secret := a_secret_key + cx := a_cx + query := a_query + ensure + secret_set: secret.same_string (a_secret_key) + cx_set: cx.same_string (a_cx) + query_set: query.same_string (a_query) + end + +feature -- Access : Required Parameters + + secret: READABLE_STRING_8 + -- Required. The shared key between your site and Google Custom Search Engine. + + cx: READABLE_STRING_8 + -- Custom search engine id to perform this search. + + query: READABLE_STRING_8 + -- Search query, query parameter to specify your search expression. + +feature -- Optional Parameters + +--Optional parameters +--c2coff string Enables or disables Simplified and Traditional Chinese Search. +-- The default value for this parameter is 0 (zero), meaning that the feature is enabled. Supported values are: +-- 1: Disabled +-- 0: Enabled (default) +--cr string Restricts search results to documents originating in a particular country. +-- You may use Boolean operators in the cr parameter's value. +-- Google Search determines the country of a document by analyzing: +-- the top-level domain (TLD) of the document's URL +-- the geographic location of the Web server's IP address +-- See the Country Parameter Values page for a list of valid values for this parameter. +--cref string The URL of a linked custom search engine specification to use for this request. +-- Does not apply for Google Site Search +-- If both cx and cref are specified, the cx value is used +--cx string The custom search engine ID to use for this request. +-- If both cx and cref are specified, the cx value is used. +--dateRestrict string Restricts results to URLs based on date. Supported values include: +-- d[number]: requests results from the specified number of past days. +-- w[number]: requests results from the specified number of past weeks. +-- m[number]: requests results from the specified number of past months. +-- y[number]: requests results from the specified number of past years. +--exactTerms string Identifies a phrase that all documents in the search results must contain. +--excludeTerms string Identifies a word or phrase that should not appear in any documents in the search results. +--fileType string Restricts results to files of a specified extension. A list of file types indexable by Google can be found in Webmaster Tools Help Center. +--filter string Controls turning on or off the duplicate content filter. +-- See Automatic Filtering for more information about Google's search results filters. Note that host crowding filtering applies only to multi-site searches. +-- By default, Google applies filtering to all search results to improve the quality of those results. + + +-- Acceptable values are: +-- "0": Turns off duplicate content filter. +-- "1": Turns on duplicate content filter. +-- gl string Geolocation of end user. +--The gl parameter value is a two-letter country code. The gl parameter boosts search results whose country of origin matches the parameter value. See the Country Codes page for a list of valid values. +--Specifying a gl parameter value should lead to more relevant results. This is particularly true for international customers and, even more specifically, for customers in English- speaking countries other than the United States. +--googlehost string The local Google domain (for example, google.com, google.de, or google.fr) to use to perform the search. +--highRange string +--Specifies the ending value for a search range. +--Use lowRange and highRange to append an inclusive search range of lowRange...highRange to the query. +--hl string Sets the user interface language. +--Explicitly setting this parameter improves the performance and the quality of your search results. +--See the Interface Languages section of Internationalizing Queries and Results Presentation for more information, and Supported Interface Languages for a list of supported languages. +--hq string Appends the specified query terms to the query, as if they were combined with a logical AND operator. +--imgColorType string Returns black and white, grayscale, or color images: mono, gray, and color. + +-- Acceptable values are: +-- "color": color +-- "gray": gray +-- "mono": mono +--imgDominantColor string Returns images of a specific dominant color. + +-- Acceptable values are: +-- "black": black +-- "blue": blue +-- "brown": brown +-- "gray": gray +-- "green": green +-- "pink": pink +-- "purple": purple +-- "teal": teal +-- "white": white +-- "yellow": yellow +--imgSize string Returns images of a specified size. + +-- Acceptable values are: +-- "huge": huge +-- "icon": icon +-- "large": large +-- "medium": medium +-- "small": small +-- "xlarge": xlarge +-- "xxlarge": xxlarge +--imgType string Returns images of a type. + +-- Acceptable values are: +-- "clipart": clipart +-- "face": face +-- "lineart": lineart +-- "news": news +-- "photo": photo +--linkSite string Specifies that all search results should contain a link to a particular URL +--lowRange string Specifies the starting value for a search range. +--Use lowRange and highRange to append an inclusive search range of lowRange...highRange to the query. +--lr string Restricts the search to documents written in a particular language (e.g., lr=lang_ja). + +-- Acceptable values are: +-- "lang_ar": Arabic +-- "lang_bg": Bulgarian +-- "lang_ca": Catalan +-- "lang_cs": Czech +-- "lang_da": Danish +-- "lang_de": German +-- "lang_el": Greek +-- "lang_en": English +-- "lang_es": Spanish +-- "lang_et": Estonian +-- "lang_fi": Finnish +-- "lang_fr": French +-- "lang_hr": Croatian +-- "lang_hu": Hungarian +-- "lang_id": Indonesian +-- "lang_is": Icelandic +-- "lang_it": Italian +-- "lang_iw": Hebrew +-- "lang_ja": Japanese +-- "lang_ko": Korean +-- "lang_lt": Lithuanian +-- "lang_lv": Latvian +-- "lang_nl": Dutch +-- "lang_no": Norwegian +-- "lang_pl": Polish +-- "lang_pt": Portuguese +-- "lang_ro": Romanian +-- "lang_ru": Russian +-- "lang_sk": Slovak +-- "lang_sl": Slovenian +-- "lang_sr": Serbian +-- "lang_sv": Swedish +-- "lang_tr": Turkish +-- "lang_zh-CN": Chinese (Simplified) +-- "lang_zh-TW": Chinese (Traditional) + +--orTerms string Provides additional search terms to check for in a document, where each document in the search results must contain at least one of the additional search terms. +--relatedSite string Specifies that all search results should be pages that are related to the specified URL. +--rights string Filters based on licensing. Supported values include: cc_publicdomain, cc_attribute, cc_sharealike, cc_noncommercial, cc_nonderived, and combinations of these. +--safe string Search safety level. + +-- Acceptable values are: +-- "high": Enables highest level of SafeSearch filtering. +-- "medium": Enables moderate SafeSearch filtering. +-- "off": Disables SafeSearch filtering. (default) +--searchType string Specifies the search type: image. If unspecified, results are limited to webpages. + +--Acceptable values are: +-- "image": custom image search. +--siteSearch string Specifies all search results should be pages from a given site. +--siteSearchFilter string Controls whether to include or exclude results from the site named in the siteSearch parameter. + +-- Acceptable values are: +-- "e": exclude +-- "i": include +-- sort string The sort expression to apply to the results. +-- + + + num : detachable STRING_8 + -- Number of search results to return. + -- Valid values are integers between 1 and 10, inclusive. + + start: detachable STRING_8 + -- The index of the first result to return. + + +feature -- Change Elements + + set_num (a_num: READABLE_STRING_8) + require + is_number: a_num.is_integer + valid_range: a_num.to_integer >= 1 and then a_num.to_integer <= 10 + do + num := a_num + ensure + num_set: num = a_num + valid_rage_set: attached num as l_num and then l_num.to_integer >= 1 and then l_num.to_integer <= 10 + end + + + set_start (a_start: READABLE_STRING_8) + require + is_number: a_start.is_integer + valid_start: a_start.to_integer >= 1 + do + start := a_start + ensure + start_set: start = a_start + valid_start_set: attached start as l_start and then l_start.to_integer >= 1 + end + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/gcse/src/gcse_response.e b/library/gcse/src/gcse_response.e new file mode 100644 index 0000000..5ffdfcb --- /dev/null +++ b/library/gcse/src/gcse_response.e @@ -0,0 +1,88 @@ +note + description: "[ + Represent search request metadata + URL: search template used for the current results. + Queries: current, next and previous page. + Context + Search infromation + Items: array of actual search results. + ]" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + +class + GCSE_RESPONSE + + --! TODO + --! All suppport for for url, context and search information. + +feature -- Access + + + current_page: detachable GCSE_PAGE + -- Metadata describing the query for the current set of results. + -- This role is always present in the response. + -- It is always an array with just one element. + + next_page: detachable GCSE_PAGE + -- Metadata describing the query to use for the next page of results. + -- This role is not present if the current results are the last page. Note: This API returns up to the first 100 results only. + -- When present, it is always a array with just one element. + + previous_page: detachable GCSE_PAGE + -- Metadata describing the query to use for the previous page of results. + -- Not present if the current results are the first page. + -- When present, it is always a array with just one element. + + items: detachable LIST [GCSE_PAGE_ITEM] + -- Contains the actual search results. The search results include the URL, title and text snippets that describe the result. + +feature -- Change Element + + set_current_page (a_page: GCSE_PAGE) + -- Set `current_page' with `a_page'. + do + current_page := a_page + ensure + current_page_set: current_page = a_page + end + + set_next_page (a_page: GCSE_PAGE) + -- Set `next_page' with `a_page'. + do + next_page := a_page + ensure + next_page_set: next_page = a_page + end + + set_previous_page (a_page: GCSE_PAGE) + -- Set `previous_page' with `a_page'. + do + previous_page := a_page + ensure + previous_page_set: previous_page = a_page + end + + add_item (a_item: GCSE_PAGE_ITEM) + -- Add item `a_item' to the list of items. + local + l_items: like items + do + l_items := items + if l_items = Void then + create {ARRAYED_LIST[GCSE_PAGE_ITEM]}l_items.make (10) + items := l_items + end + l_items.force (a_item) + end +;note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" +end diff --git a/library/gcse/test/application.e b/library/gcse/test/application.e new file mode 100644 index 0000000..bdc9b06 --- /dev/null +++ b/library/gcse/test/application.e @@ -0,0 +1,80 @@ +note + description : "test application root class" + date : "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision : "$Revision: 97966 $" + +class + APPLICATION + +inherit + ARGUMENTS + +create + make + +feature {NONE} -- Initialization + + make + -- Run application. + local + gcse: GCSE_API + l_parameters: GCSE_QUERY_PARAMETERS + do + create l_parameters.make (key, cx, "scoop") + create gcse.make (l_parameters) + gcse.search + + if attached {GCSE_RESPONSE} gcse.last_result as l_result then + if attached l_result.current_page as l_page then + print ("Current Page%N") + print (l_page.to_string) + end + if attached l_result.next_page as l_page then + print ("Next Page%N") + print (l_page.to_string) + end + if attached l_result.previous_page as l_page then + print ("Previous Page%N") + print (l_page.to_string) + end + + if attached l_result.items as l_items then + print ("Number of items:" + l_items.count.out) + across l_items as ic loop print (ic.item.to_string) end + end + + if attached l_result.next_page as l_page then + l_parameters.set_start (l_page.start_index.out) + gcse.search + end + end + + if attached {GCSE_RESPONSE} gcse.last_result as l_result then + if attached l_result.current_page as l_page then + print ("Current Page%N") + print (l_page.to_string) + end + if attached l_result.next_page as l_page then + print ("Next Page%N") + print (l_page.to_string) + end + if attached l_result.previous_page as l_page then + print ("Previous Page%N") + print (l_page.to_string) + end + + if attached l_result.items as l_items then + print ("Number of items:" + l_items.count.out) + across l_items as ic loop print (ic.item.to_string) end + end + + end + + + end + +feature {NONE} -- Implementation + + Key: STRING = "AIzaSyBKAXNofo-RqZb6kUmpbiCwPEy7n7-E51k" + cx : STRING = "015017565055626880074:9gdgp1fvt-g" +end diff --git a/library/gcse/test/gcse_api_test_set.e b/library/gcse/test/gcse_api_test_set.e new file mode 100644 index 0000000..02deb68 --- /dev/null +++ b/library/gcse/test/gcse_api_test_set.e @@ -0,0 +1,31 @@ +note + description: "[ + Eiffel tests that can be executed by testing tool. + ]" + author: "EiffelStudio test wizard" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + testing: "type/manual" + +class + GCSE_API_TEST_SET + +inherit + EQA_TEST_SET + +feature -- Test routines + + +feature {NONE} -- Implementation + + has_error (l_captcha: GCSE_API; a_error: READABLE_STRING_32): BOOLEAN + do + if attached l_captcha.errors as l_errors then + l_errors.compare_objects + Result := l_errors.has (a_error) + end + end + +end + + diff --git a/library/gcse/test/test.ecf b/library/gcse/test/test.ecf new file mode 100644 index 0000000..0db0a14 --- /dev/null +++ b/library/gcse/test/test.ecf @@ -0,0 +1,21 @@ + + + + + + + + + + + + + /EIFGENs$ + /CVS$ + /.svn$ + + + + diff --git a/library/http_client_extension/http_client_extension-safe.ecf b/library/http_client_extension/http_client_extension-safe.ecf new file mode 100644 index 0000000..83979b3 --- /dev/null +++ b/library/http_client_extension/http_client_extension-safe.ecf @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + diff --git a/library/http_client_extension/http_client_extension.ecf b/library/http_client_extension/http_client_extension.ecf new file mode 100644 index 0000000..f15887d --- /dev/null +++ b/library/http_client_extension/http_client_extension.ecf @@ -0,0 +1,25 @@ + + + + + + /.git$ + /EIFGENs$ + /CVS$ + /.svn$ + + + + + + + + + + + + + + diff --git a/library/http_client_extension/src/request/request.e b/library/http_client_extension/src/request/request.e new file mode 100644 index 0000000..5d4713f --- /dev/null +++ b/library/http_client_extension/src/request/request.e @@ -0,0 +1,199 @@ +note + description: "Represent an HTTP request." + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + +class + REQUEST + +inherit + + HTTP_CONSTANTS + +create + make + +feature {NONE} -- Initialization + + make (a_method: READABLE_STRING_8; a_uri: READABLE_STRING_8) + require + valid_http_method: is_http_method (a_method) + valid_uri: is_valid_uri (a_uri) + do + verb := a_method + uri := a_uri + create headers.make (5) + ensure + ver_set: verb = a_method + uri_set: uri = a_uri + end + +feature -- Status Report + + is_valid_uri (a_uri: READABLE_STRING_8): BOOLEAN + local + l_uri: URI + do + create l_uri.make_from_string (a_uri) + Result := l_uri.is_valid + end + + query_string: detachable READABLE_STRING_8 + local + l_uri: URI + do + create l_uri.make_from_string (uri) + Result := l_uri.query + end + + sanitized_url: READABLE_STRING_8 + -- Returns the URL without the query string part + local + l_uri: URI + do + create l_uri.make_from_string (uri) + l_uri.remove_query + Result := l_uri.string + ensure + sanitized: not as_uri (Result).has_query + end + + is_http_method (a_method: READABLE_STRING_GENERAL): BOOLEAN + do + if a_method.same_string (method_connect) then + Result := True + elseif a_method.same_string (method_delete) then + Result := True + elseif a_method.same_string (method_get) then + Result := True + elseif a_method.same_string (method_head) then + Result := True + elseif a_method.same_string (method_options) then + Result := True + elseif a_method.same_string (method_patch) then + Result := True + elseif a_method.same_string (method_post) then + Result := True + elseif a_method.same_string (method_put) then + Result := True + elseif a_method.same_string (method_trace) then + Result := True + end + end + +feature -- Constants + + content_type_header_name: STRING_8 = "Content-Type"; + + default_content_type: STRING + once + Result := application_json + end + +feature -- Access + + uri: READABLE_STRING_8 + + verb: READABLE_STRING_8 + + headers: STRING_TABLE [READABLE_STRING_8] + + payload: detachable READABLE_STRING_8 + + executor: detachable REQUEST_EXECUTOR + +feature -- Change Element + + add_payload (a_payload: like payload) + do + payload := a_payload + ensure + payload_set: attached payload as l_payload implies l_payload = a_payload + end + + add_header (key: READABLE_STRING_8; value: READABLE_STRING_8) + do + headers.force (value, key) + end + +feature -- Execute + + execute: detachable RESPONSE + do + initialize_executor + Result := execute_request + end + + initialize_executor + do + create executor.make (uri, verb) + end + +feature {NONE} -- Implementation + + execute_request: detachable RESPONSE + do + if attached executor as l_executor then + -- add headers + add_headers (l_executor) + if verb.same_string (method_put) or else verb.same_string (method_post) or else verb.same_string (method_patch) then + l_executor.set_body (body_contents) + end + if not l_executor.context_executor.headers.has (content_type_header_name) then + l_executor.context_executor.add_header (content_type_header_name, default_content_type) + end + if attached l_executor.execute as l_response then + create Result.make (l_response) + end + end + end + +feature {NONE} -- Implementation + + add_headers (a_executor: REQUEST_EXECUTOR) + local + l_context_executor: HTTP_CLIENT_REQUEST_CONTEXT + s: READABLE_STRING_GENERAL + utf: UTF_CONVERTER + do + l_context_executor := a_executor.context_executor + across + headers as ic + loop + s := ic.key + if s.is_valid_as_string_8 then + l_context_executor.add_header (s.as_string_8, ic.item) + else + l_context_executor.add_header (utf.utf_32_string_to_utf_8_string_8 (s), ic.item) + end + end + end + + body_contents: READABLE_STRING_8 + do + if attached payload as l_payload then + Result := l_payload + else + Result := "" + end + end + + as_uri (a_string: READABLE_STRING_8): URI + require + is_valid_uri: is_valid_uri (a_string) + do + create Result.make_from_string (a_string) + end + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/http_client_extension/src/request/request_executor.e b/library/http_client_extension/src/request/request_executor.e new file mode 100644 index 0000000..0e0e5d0 --- /dev/null +++ b/library/http_client_extension/src/request/request_executor.e @@ -0,0 +1,97 @@ +note + description: "Executes an HTTP request" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + +class + REQUEST_EXECUTOR + +inherit + + HTTP_CLIENT_HELPER + + HTTP_CONSTANTS + +create + make + +feature {NONE} -- Initialization + + make (a_url: READABLE_STRING_8; a_method: READABLE_STRING_8) + do + set_base_url (a_url) + verb := a_method + ensure + base_url_set: base_url.same_string (a_url) + method_set: verb.same_string (a_method) + end + + set_base_url (a_url: READABLE_STRING_8) + -- Set base_url with `a_url' + local + s: STRING + do + create s.make_from_string (a_url) + s.left_adjust + s.right_adjust + base_url := s + ensure + base_url_set: a_url.has_substring (base_url) + end + +feature -- Access + + verb: READABLE_STRING_8 + -- HTTP METHOD (Get, Post, ...) + + body: detachable READABLE_STRING_8 + -- body content + +feature -- Element Change + + set_body (a_body: like body) + -- Set body with `a_body'. + do + body := a_body + ensure + body_set: body = a_body + end + +feature -- Execute + + execute: detachable HTTP_CLIENT_RESPONSE + -- Http executor + do + if verb.same_string (method_connect) then + Result := Void -- not supported for now + elseif verb.same_string (method_delete) then + Result := execute_delete ("") + elseif verb.same_string (method_get) then + Result := execute_get ("") + elseif verb.same_string (method_head) then + Result := Void + elseif verb.same_string (method_options) then + Result := Void + elseif verb.same_string (method_patch) then + Result := execute_patch ("", body) + elseif verb.same_string (method_post) then + Result := execute_post ("", body) + elseif verb.same_string (method_put) then + Result := execute_put ("", body) + elseif verb.same_string (method_trace) then + Result := Void + end + end + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/http_client_extension/src/response/response.e b/library/http_client_extension/src/response/response.e new file mode 100644 index 0000000..4ee711a --- /dev/null +++ b/library/http_client_extension/src/response/response.e @@ -0,0 +1,57 @@ +note + description: "Represent and HTTP Response" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + +class + RESPONSE + +create + make + +feature {NONE} --Initialization + + make (a_response: HTTP_CLIENT_RESPONSE) + do + http_response := a_response + body := a_response.body + status := a_response.status + headers := a_response.headers + status_message := a_response.status_line + error_message := a_response.error_message + ensure + http_reponse_set: http_response = a_response + headers_set: headers = a_response.headers + status_set: status = a_response.status + status_message_set: status_message = a_response.status_line + error_message_set: error_message = a_response.error_message + end + +feature -- Access + + status: INTEGER + + status_message: detachable READABLE_STRING_8 + + error_message: detachable READABLE_STRING_8 + + body: detachable READABLE_STRING_8 + + headers: LIST [TUPLE [name: READABLE_STRING_8; value: READABLE_STRING_8]] + +feature {NONE} -- Implementation + + http_response: HTTP_CLIENT_RESPONSE; + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/library/http_client_extension/src/util/http_client_helper.e b/library/http_client_extension/src/util/http_client_helper.e new file mode 100644 index 0000000..f120da2 --- /dev/null +++ b/library/http_client_extension/src/util/http_client_helper.e @@ -0,0 +1,99 @@ +note + description: "Wrapper class for HTTP_CLIENT_SESSION" + date: "$Date: 2015-10-08 07:51:29 -0300 (ju., 08 oct. 2015) $" + revision: "$Revision: 97966 $" + +deferred class + HTTP_CLIENT_HELPER + +feature -- Access + + http_session: detachable HTTP_CLIENT_SESSION + + get_http_session + local + h: LIBCURL_HTTP_CLIENT + b: like base_url + do + create h.make + b := base_url + if b = Void then + b := "" + end + if attached {HTTP_CLIENT_SESSION} h.new_session (base_url) as sess then + http_session := sess + sess.set_timeout (-1) + sess.set_connect_timeout (-1) + sess.set_is_insecure (True) + sess.set_any_auth_type + debug ("curl") + sess.set_is_debug (True) + end + debug ("proxy8888") + sess.set_proxy ("127.0.0.1", 8888) --| inspect traffic with http://www.fiddler2.com/ + end + end + end + +feature -- HTTP client helpers + + execute_get (command_name: READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + get_http_session + if attached http_session as sess then + Result := sess.get (command_name, context_executor) + end + end + + execute_post (command_name: READABLE_STRING_8; data: detachable READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + get_http_session + if attached http_session as sess then + Result := sess.post (command_name, context_executor, data) + end + end + + execute_delete (command_name: READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + get_http_session + if attached http_session as sess then + Result := sess.delete (command_name, context_executor) + end + end + + execute_put (command_name: READABLE_STRING_8; data: detachable READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + get_http_session + if attached http_session as sess then + Result := sess.put (command_name, context_executor, data) + end + end + + execute_patch (command_name: READABLE_STRING_8; data: detachable READABLE_STRING_8): detachable HTTP_CLIENT_RESPONSE + do + get_http_session + if attached http_session as sess then + Result := sess.patch (command_name, context_executor, data) + end + end + + context_executor: HTTP_CLIENT_REQUEST_CONTEXT + -- request context for each request + once + create Result.make + end + + base_url: STRING; + +note + copyright: "2011-2015 Javier Velilla, Jocelyn Fiat, Eiffel Software and others" + license: "Eiffel Forum License v2 (see http://www.eiffel.com/licensing/forum.txt)" + source: "[ + Eiffel Software + 5949 Hollister Ave., Goleta, CA 93117 USA + Telephone 805-685-1006, Fax 805-685-6869 + Website http://www.eiffel.com + Customer support http://support.eiffel.com + ]" + +end diff --git a/modules/auth/cms_authentication_module.e b/modules/auth/cms_authentication_module.e index 21e59b1..5c786bb 100644 --- a/modules/auth/cms_authentication_module.e +++ b/modules/auth/cms_authentication_module.e @@ -123,6 +123,7 @@ feature -- Hooks configuration lnk.set_weight (98) a_menu_system.primary_menu.extend (lnk) end + end feature -- Handler diff --git a/modules/custom_search/Readme.md b/modules/custom_search/Readme.md new file mode 100644 index 0000000..279cd07 --- /dev/null +++ b/modules/custom_search/Readme.md @@ -0,0 +1 @@ +Google Custom Search Module. \ No newline at end of file diff --git a/modules/custom_search/custom_search.ecf b/modules/custom_search/custom_search.ecf new file mode 100644 index 0000000..35bdfe6 --- /dev/null +++ b/modules/custom_search/custom_search.ecf @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/modules/custom_search/site/config/custom_search.json b/modules/custom_search/site/config/custom_search.json new file mode 100644 index 0000000..9b7ab8c --- /dev/null +++ b/modules/custom_search/site/config/custom_search.json @@ -0,0 +1,6 @@ +{ + "gcse": { + "cx":"", + "secret_key":"" + } +} diff --git a/modules/custom_search/site/templates/block_search.tpl b/modules/custom_search/site/templates/block_search.tpl new file mode 100644 index 0000000..d37d146 --- /dev/null +++ b/modules/custom_search/site/templates/block_search.tpl @@ -0,0 +1,40 @@ +
+
+

Results for {$result.current_page.search_terms/}

+
+ + +
    + + + {foreach from="$result.items" item="item"} +
  1. + +
  2. + {/foreach} + + +
+ +
\ No newline at end of file diff --git a/modules/custom_search/src/google_custom_search_module.e b/modules/custom_search/src/google_custom_search_module.e new file mode 100644 index 0000000..0d7267e --- /dev/null +++ b/modules/custom_search/src/google_custom_search_module.e @@ -0,0 +1,154 @@ +note + description: "[ + Module that provide Google Custom Search functionality. + ]" + date: "$Date: 2015-10-09 20:50:01 -0300 (vi. 09 de oct. de 2015) $" + revision: "$Revision: 97982 $" + +class + GOOGLE_CUSTOM_SEARCH_MODULE + +inherit + + CMS_MODULE + redefine + register_hooks + end + + CMS_HOOK_BLOCK_HELPER + + CMS_HOOK_AUTO_REGISTER + + CMS_HOOK_MENU_SYSTEM_ALTER + + SHARED_EXECUTION_ENVIRONMENT + export + {NONE} all + end + + REFACTORING_HELPER + + SHARED_LOGGER + +create + make + +feature {NONE} -- Initialization + + make + -- Create current module + do + version := "1.0" + description := "Google custome search module" + package := "search" + end + +feature -- Access + + name: STRING = "custom_search" + -- + +feature -- Router + + setup_router (a_router: WSF_ROUTER; a_api: CMS_API) + -- Router configuration. + do + a_router.handle ("/gcse", create {WSF_URI_AGENT_HANDLER}.make (agent handle_search (a_api, ?, ?)), a_router.methods_head_get) + end + +feature -- Recaptcha + + gcse_secret_key (api: CMS_API): detachable READABLE_STRING_8 + -- Get recaptcha security key. + local + utf: UTF_CONVERTER + do + if attached api.module_configuration (Current, Void) as cfg then + if + attached cfg.text_item ("gcse.secret_key") as l_recaptcha_key and then + not l_recaptcha_key.is_empty + then + Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + end + end + end + + gcse_cx_key (api: CMS_API): detachable READABLE_STRING_8 + -- Get recaptcha security key. + local + utf: UTF_CONVERTER + do + if attached api.module_configuration (Current, Void) as cfg then + if + attached cfg.text_item ("gcse.cx") as l_recaptcha_key and then + not l_recaptcha_key.is_empty + then + Result := utf.utf_32_string_to_utf_8_string_8 (l_recaptcha_key) + end + end + end + +feature -- Hooks configuration + + register_hooks (a_response: CMS_RESPONSE) + -- Module hooks configuration. + do + auto_subscribe_to_hooks (a_response) + end + +feature -- Hooks + + menu_system_alter (a_menu_system: CMS_MENU_SYSTEM; a_response: CMS_RESPONSE) + -- Hook execution on collection of menu contained by `a_menu_system' + -- for related response `a_response'. + do + end + + block_list: ITERABLE [like {CMS_BLOCK}.name] + do + Result := <<"search">> + end + +feature -- Handler + + handle_search (api: CMS_API; req: WSF_REQUEST; res: WSF_RESPONSE) + local + r: CMS_RESPONSE + l_parameters:GCSE_QUERY_PARAMETERS + l_search: GCSE_API + do + -- TODO handle errors!!! + write_debug_log (generator + ".handle_search") + create {GENERIC_VIEW_CMS_RESPONSE} r.make (req, res, api) + if attached {WSF_STRING} req.query_parameter ("q") as l_query then + if + attached gcse_cx_key (api) as l_cx and then + attached gcse_secret_key (api) as l_key + then + create l_parameters.make (l_key, l_cx, l_query.value ) + if + attached {WSF_STRING} req.query_parameter ("start") as l_index and then + attached {WSF_STRING} req.query_parameter ("num") as l_num + then + l_parameters.set_start (l_index.value) + l_parameters.set_num (l_num.value) + end + create l_search.make (l_parameters) + l_search.search + if attached template_block (Current, "search", r) as l_tpl_block then + l_tpl_block.set_value (l_search.last_result, "result") + r.add_block (l_tpl_block, "content") + end + else + -- If no key are provided, at least output google search result page. + if req.is_https then + r.set_redirection ("https://www.google.com/search?sitesearch=" + r.absolute_url ("", Void) + "&q=" + l_query.url_encoded_value) + else + r.set_redirection ("http://www.google.com/search?sitesearch=" + r.absolute_url ("", Void) + "&q=" + l_query.url_encoded_value) + end + end + end + r.execute + end + +end