elastic-workplace-search 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (34) hide show
  1. checksums.yaml +7 -0
  2. data/.circleci/config.yml +68 -0
  3. data/.gitignore +10 -0
  4. data/.travis.yml +15 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +201 -0
  7. data/NOTICE.txt +3 -0
  8. data/README.md +171 -0
  9. data/Rakefile +1 -0
  10. data/elastic-workplace-search.gemspec +23 -0
  11. data/lib/data/ca-bundle.crt +3554 -0
  12. data/lib/elastic-workplace-search.rb +1 -0
  13. data/lib/elastic/workplace-search.rb +7 -0
  14. data/lib/elastic/workplace-search/client.rb +53 -0
  15. data/lib/elastic/workplace-search/client/content_source_documents.rb +45 -0
  16. data/lib/elastic/workplace-search/client/permissions.rb +29 -0
  17. data/lib/elastic/workplace-search/configuration.rb +54 -0
  18. data/lib/elastic/workplace-search/exceptions.rb +11 -0
  19. data/lib/elastic/workplace-search/request.rb +113 -0
  20. data/lib/elastic/workplace-search/utils.rb +15 -0
  21. data/lib/elastic/workplace-search/version.rb +5 -0
  22. data/spec/client/content_source_documents_spec.rb +55 -0
  23. data/spec/client/permissions_spec.rb +75 -0
  24. data/spec/configuration_spec.rb +19 -0
  25. data/spec/fixtures/vcr/add_user_permissions.yml +55 -0
  26. data/spec/fixtures/vcr/async_create_or_update_document_success.yml +51 -0
  27. data/spec/fixtures/vcr/destroy_documents_success.yml +51 -0
  28. data/spec/fixtures/vcr/get_user_permissions.yml +55 -0
  29. data/spec/fixtures/vcr/list_all_permissions.yml +55 -0
  30. data/spec/fixtures/vcr/list_all_permissions_with_paging.yml +55 -0
  31. data/spec/fixtures/vcr/remove_user_permissions.yml +55 -0
  32. data/spec/fixtures/vcr/update_user_permissions.yml +55 -0
  33. data/spec/spec_helper.rb +28 -0
  34. metadata +143 -0
@@ -0,0 +1 @@
1
+ require 'elastic/workplace-search'
@@ -0,0 +1,7 @@
1
+ require 'elastic/workplace-search/client'
2
+
3
+ module Elastic
4
+ module WorkplaceSearch
5
+ extend Elastic::WorkplaceSearch::Configuration
6
+ end
7
+ end
@@ -0,0 +1,53 @@
1
+ require 'set'
2
+ require 'elastic/workplace-search/configuration'
3
+ require 'elastic/workplace-search/request'
4
+ require 'elastic/workplace-search/utils'
5
+
6
+ module Elastic
7
+ module WorkplaceSearch
8
+ # API client for the {Elastic Workplace Search API}[https://www.elastic.co/workplace-search].
9
+ class Client
10
+ autoload :ContentSourceDocuments, 'elastic/workplace-search/client/content_source_documents.rb'
11
+ autoload :Permissions, 'elastic/workplace-search/client/permissions.rb'
12
+
13
+ DEFAULT_TIMEOUT = 15
14
+
15
+ include Elastic::WorkplaceSearch::Request
16
+
17
+ def self.configure(&block)
18
+ Elastic::WorkplaceSearch.configure &block
19
+ end
20
+
21
+ # Create a new Elastic::WorkplaceSearch::Client client
22
+ #
23
+ # @param options [Hash] a hash of configuration options that will override what is set on the Elastic::WorkplaceSearch class.
24
+ # @option options [String] :access_token an Access Token to use for this client
25
+ # @option options [Numeric] :overall_timeout overall timeout for requests in seconds (default: 15s)
26
+ # @option options [Numeric] :open_timeout the number of seconds Net::HTTP (default: 15s)
27
+ # will wait while opening a connection before raising a Timeout::Error
28
+ # @option options [String] :proxy url of proxy to use, ex: "http://localhost:8888"
29
+ def initialize(options = {})
30
+ @options = options
31
+ end
32
+
33
+ def access_token
34
+ @options[:access_token] || Elastic::WorkplaceSearch.access_token
35
+ end
36
+
37
+ def open_timeout
38
+ @options[:open_timeout] || DEFAULT_TIMEOUT
39
+ end
40
+
41
+ def proxy
42
+ @options[:proxy]
43
+ end
44
+
45
+ def overall_timeout
46
+ (@options[:overall_timeout] || DEFAULT_TIMEOUT).to_f
47
+ end
48
+
49
+ include Elastic::WorkplaceSearch::Client::ContentSourceDocuments
50
+ include Elastic::WorkplaceSearch::Client::Permissions
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,45 @@
1
+ module Elastic
2
+ module WorkplaceSearch
3
+ class Client
4
+ module ContentSourceDocuments
5
+
6
+ # Index a batch of documents.
7
+ #
8
+ # @param [String] content_source_key the unique Content Source key as found in your Content Sources dashboard
9
+ # @param [Array] documents an Array of Document Hashes
10
+ #
11
+ # @return [Array<Hash>] an Array of Document indexing Results
12
+ #
13
+ # @raise [Elastic::WorkplaceSearch::InvalidDocument] when a single document is missing required fields or contains unsupported fields
14
+ # @raise [Timeout::Error] when timeout expires waiting for results
15
+ def index_documents(content_source_key, documents)
16
+ documents = Array(documents).map! { |document| normalize_document(document) }
17
+
18
+ async_create_or_update_documents(content_source_key, documents)
19
+ end
20
+
21
+ # Destroy a batch of documents given a list of external IDs
22
+ #
23
+ # @param [Array<String>] document_ids an Array of Document External IDs
24
+ #
25
+ # @return [Array<Hash>] an Array of Document destroy result hashes
26
+ #
27
+ # @raise [Timeout::Error] when timeout expires waiting for results
28
+ def destroy_documents(content_source_key, document_ids)
29
+ document_ids = Array(document_ids)
30
+ post("sources/#{content_source_key}/documents/bulk_destroy.json", document_ids)
31
+ end
32
+
33
+ private
34
+
35
+ def async_create_or_update_documents(content_source_key, documents)
36
+ post("sources/#{content_source_key}/documents/bulk_create.json", documents)
37
+ end
38
+
39
+ def normalize_document(document)
40
+ Utils.stringify_keys(document)
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,29 @@
1
+ module Elastic
2
+ module WorkplaceSearch
3
+ class Client
4
+ module Permissions
5
+
6
+ def list_all_permissions(content_source_key, current: 1, size: 25)
7
+ get("sources/#{content_source_key}/permissions", "page[current]" => current, "page[size]" => size )
8
+ end
9
+
10
+ def get_user_permissions(content_source_key, user)
11
+ get("sources/#{content_source_key}/permissions/#{user}")
12
+ end
13
+
14
+ def update_user_permissions(content_source_key, user, options)
15
+ post("sources/#{content_source_key}/permissions/#{user}", options)
16
+ end
17
+
18
+ def add_user_permissions(content_source_key, user, options)
19
+ post("sources/#{content_source_key}/permissions/#{user}/add", options)
20
+ end
21
+
22
+ def remove_user_permissions(content_source_key, user, options)
23
+ post("sources/#{content_source_key}/permissions/#{user}/remove", options)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,54 @@
1
+ require 'uri'
2
+ require 'elastic/workplace-search/version'
3
+
4
+ module Elastic
5
+ module WorkplaceSearch
6
+ module Configuration
7
+ DEFAULT_ENDPOINT = "http://localhost:3002/api/ws/v1/"
8
+
9
+ VALID_OPTIONS_KEYS = [
10
+ :access_token,
11
+ :user_agent,
12
+ :endpoint
13
+ ].freeze
14
+
15
+ attr_accessor *VALID_OPTIONS_KEYS
16
+
17
+ def self.extended(base)
18
+ base.reset
19
+ end
20
+
21
+ # Reset configuration to default values.
22
+ def reset
23
+ self.access_token = nil
24
+ self.endpoint = DEFAULT_ENDPOINT
25
+ self.user_agent = nil
26
+ self
27
+ end
28
+
29
+ # Yields the Elastic::WorkplaceSearch::Configuration module which can be used to set configuration options.
30
+ #
31
+ # @return self
32
+ def configure
33
+ yield self
34
+ self
35
+ end
36
+
37
+ # Return a hash of the configured options.
38
+ def options
39
+ options = {}
40
+ VALID_OPTIONS_KEYS.each{ |k| options[k] = send(k) }
41
+ options
42
+ end
43
+
44
+ # setter for endpoint that ensures it always ends in '/'
45
+ def endpoint=(endpoint)
46
+ if endpoint.end_with?('/')
47
+ @endpoint = endpoint
48
+ else
49
+ @endpoint = "#{endpoint}/"
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,11 @@
1
+ module Elastic
2
+ module WorkplaceSearch
3
+ class ClientException < StandardError; end
4
+ class NonExistentRecord < ClientException; end
5
+ class InvalidCredentials < ClientException; end
6
+ class BadRequest < ClientException; end
7
+ class Forbidden < ClientException; end
8
+ class UnexpectedHTTPException < ClientException; end
9
+ class InvalidDocument < ClientException; end
10
+ end
11
+ end
@@ -0,0 +1,113 @@
1
+ require 'net/https'
2
+ require 'json'
3
+ require 'elastic/workplace-search/exceptions'
4
+ require 'openssl'
5
+
6
+ module Elastic
7
+ module WorkplaceSearch
8
+ CLIENT_NAME = 'elastic-workplace-search-ruby'
9
+ CLIENT_VERSION = Elastic::WorkplaceSearch::VERSION
10
+
11
+ module Request
12
+ def get(path, params={})
13
+ request(:get, path, params)
14
+ end
15
+
16
+ def post(path, params={})
17
+ request(:post, path, params)
18
+ end
19
+
20
+ def put(path, params={})
21
+ request(:put, path, params)
22
+ end
23
+
24
+ def delete(path, params={})
25
+ request(:delete, path, params)
26
+ end
27
+
28
+ # Construct and send a request to the API.
29
+ #
30
+ # @raise [Timeout::Error] when the timeout expires
31
+ def request(method, path, params = {})
32
+ Timeout.timeout(overall_timeout) do
33
+ uri = URI.parse("#{Elastic::WorkplaceSearch.endpoint}#{path}")
34
+
35
+ request = build_request(method, uri, params)
36
+
37
+ if proxy
38
+ proxy_parts = URI.parse(proxy)
39
+ http = Net::HTTP.new(uri.host, uri.port, proxy_parts.host, proxy_parts.port, proxy_parts.user, proxy_parts.password)
40
+ else
41
+ http = Net::HTTP.new(uri.host, uri.port)
42
+ end
43
+
44
+ http.open_timeout = open_timeout
45
+ http.read_timeout = overall_timeout
46
+
47
+ if uri.scheme == 'https'
48
+ http.use_ssl = true
49
+ # st_ssl_verify_none provides a means to disable SSL verification for debugging purposes. An example
50
+ # is Charles, which uses a self-signed certificate in order to inspect https traffic. This will
51
+ # not be part of this client's public API, this is more of a development enablement option
52
+ http.verify_mode = ENV['st_ssl_verify_none'] == 'true' ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER
53
+ http.ca_file = File.realpath(File.join(File.dirname(__FILE__), '..', '..', 'data', 'ca-bundle.crt'))
54
+ http.ssl_timeout = open_timeout
55
+ end
56
+
57
+ response = http.request(request)
58
+ handle_errors(response)
59
+ JSON.parse(response.body) if response.body && response.body.strip != ''
60
+ end
61
+ end
62
+
63
+ private
64
+ def handle_errors(response)
65
+ case response
66
+ when Net::HTTPSuccess
67
+ response
68
+ when Net::HTTPUnauthorized
69
+ raise Elastic::WorkplaceSearch::InvalidCredentials
70
+ when Net::HTTPNotFound
71
+ raise Elastic::WorkplaceSearch::NonExistentRecord
72
+ when Net::HTTPBadRequest
73
+ raise Elastic::WorkplaceSearch::BadRequest, "#{response.code} #{response.body}"
74
+ when Net::HTTPForbidden
75
+ raise Elastic::WorkplaceSearch::Forbidden
76
+ else
77
+ raise Elastic::WorkplaceSearch::UnexpectedHTTPException, "#{response.code} #{response.body}"
78
+ end
79
+ end
80
+
81
+ def build_request(method, uri, params)
82
+ klass = case method
83
+ when :get
84
+ Net::HTTP::Get
85
+ when :post
86
+ Net::HTTP::Post
87
+ when :put
88
+ Net::HTTP::Put
89
+ when :delete
90
+ Net::HTTP::Delete
91
+ end
92
+
93
+ case method
94
+ when :get, :delete
95
+ uri.query = URI.encode_www_form(params) if params && !params.empty?
96
+ req = klass.new(uri.request_uri)
97
+ when :post, :put
98
+ req = klass.new(uri.request_uri)
99
+ req.body = JSON.generate(params) unless params.length == 0
100
+ end
101
+
102
+ req['User-Agent'] = Elastic::WorkplaceSearch.user_agent if Elastic::WorkplaceSearch.user_agent
103
+ req['Content-Type'] = 'application/json'
104
+ req['X-Swiftype-Client'] = CLIENT_NAME
105
+ req['X-Swiftype-Client-Version'] = CLIENT_VERSION
106
+ req['Authorization'] = "Bearer #{access_token}"
107
+ puts req
108
+
109
+ req
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,15 @@
1
+ module Elastic
2
+ module WorkplaceSearch
3
+ module Utils
4
+ extend self
5
+
6
+ def stringify_keys(hash)
7
+ output = {}
8
+ hash.each do |key, value|
9
+ output[key.to_s] = value
10
+ end
11
+ output
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Elastic
2
+ module WorkplaceSearch
3
+ VERSION = '0.4.0'
4
+ end
5
+ end
@@ -0,0 +1,55 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elastic::WorkplaceSearch::Client::ContentSourceDocuments do
4
+ let(:engine_slug) { 'workplace-search-api-example' }
5
+ let(:client) { Elastic::WorkplaceSearch::Client.new }
6
+
7
+ before :each do
8
+ Elastic::WorkplaceSearch.access_token = 'cGUN-vBokevBhhzyA669'
9
+ end
10
+
11
+ def check_receipt_response_format(response, options = {})
12
+ expect(response.keys).to match_array(["document_receipts", "batch_link"])
13
+ expect(response["document_receipts"]).to be_a_kind_of(Array)
14
+ expect(response["document_receipts"].first.keys).to match_array(["id", "id", "links", "status", "errors"])
15
+ expect(response["document_receipts"].first["id"]).to eq(options[:id]) if options[:id]
16
+ expect(response["document_receipts"].first["status"]).to eq(options[:status]) if options[:status]
17
+ expect(response["document_receipts"].first["errors"]).to eq(options[:errors]) if options[:errors]
18
+ end
19
+
20
+ let(:content_source_key) { '59542d332139de0acacc7dd4' }
21
+ let(:documents) do
22
+ [{'id'=>'INscMGmhmX4',
23
+ 'url' => 'http://www.youtube.com/watch?v=v1uyQZNg2vE',
24
+ 'title' => 'The Original Grumpy Cat',
25
+ 'body' => 'this is a test'},
26
+ {'id'=>'JNDFojsd02',
27
+ 'url' => 'http://www.youtube.com/watch?v=tsdfhk2j',
28
+ 'title' => 'Another Grumpy Cat',
29
+ 'body' => 'this is also a test'}]
30
+ end
31
+
32
+ context '#index_documents' do
33
+ it 'returns results when successful' do
34
+ VCR.use_cassette(:async_create_or_update_document_success) do
35
+ response = client.index_documents(content_source_key, documents)
36
+ expect(response.size).to eq(2)
37
+ end
38
+ end
39
+ end
40
+
41
+ context '#destroy_documents' do
42
+ it 'returns #async_create_or_update_documents format return when async has been passed as true' do
43
+ VCR.use_cassette(:async_create_or_update_document_success) do
44
+ VCR.use_cassette(:document_receipts_multiple_complete) do
45
+ client.index_documents(content_source_key, documents)
46
+ VCR.use_cassette(:destroy_documents_success) do
47
+ response = client.destroy_documents(content_source_key, [documents.first['id']])
48
+ expect(response.size).to eq(1)
49
+ expect(response.first['success']).to eq(true)
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,75 @@
1
+ require 'spec_helper'
2
+
3
+ describe Elastic::WorkplaceSearch::Client::Permissions do
4
+ let(:client) { Elastic::WorkplaceSearch::Client.new }
5
+
6
+ before :each do
7
+ Elastic::WorkplaceSearch.access_token = 'xyT3mm3ecPsPuYxd_6fX'
8
+ end
9
+
10
+ let(:content_source_key) { '5d96387b75444bf49532c24a' }
11
+ let(:user) { 'enterprise_search' }
12
+
13
+ context '#list_all_permissions' do
14
+ it 'lists all permissions' do
15
+ VCR.use_cassette(:list_all_permissions) do
16
+ response = client.list_all_permissions(content_source_key)
17
+ expect(response['results'].size).to eq(2)
18
+ end
19
+ end
20
+
21
+ it 'lists all permissions with paging' do
22
+ VCR.use_cassette(:list_all_permissions_with_paging) do
23
+ response = client.list_all_permissions(content_source_key, :current => 2, :size => 5)
24
+ expect(response['meta']['page']['current']).to eq(2)
25
+ expect(response['meta']['page']['size']).to eq(5)
26
+ expect(response['results'].size).to eq(0)
27
+ end
28
+ end
29
+ end
30
+
31
+ context '#add_user_permissions' do
32
+ let(:permissions) { ['permission1'] }
33
+
34
+ it 'adds permissions to a user' do
35
+ VCR.use_cassette(:add_user_permissions) do
36
+ response = client.add_user_permissions(content_source_key, user, :permissions => permissions)
37
+ expect(response['permissions']).to eq(['permission1'])
38
+ end
39
+ end
40
+ end
41
+
42
+ context '#get_user_permissions' do
43
+ let(:permissions) { ['permission1'] }
44
+
45
+ it 'gets permissions for a user' do
46
+ VCR.use_cassette(:get_user_permissions) do
47
+ response = client.get_user_permissions(content_source_key, user)
48
+ expect(response['permissions']).to eq(['permission1'])
49
+ end
50
+ end
51
+ end
52
+
53
+ context '#update_user_permissions' do
54
+ let(:permissions) { ['permission2'] }
55
+
56
+ it 'updates permissions for a user' do
57
+ VCR.use_cassette(:update_user_permissions) do
58
+ response = client.update_user_permissions(content_source_key, user, :permissions => permissions)
59
+ expect(response['permissions']).to eq(['permission2'])
60
+ end
61
+ end
62
+ end
63
+
64
+ context '#remove_user_permissions' do
65
+ let(:permissions) { ['permission2'] }
66
+
67
+ it 'removes permissions from a user' do
68
+ VCR.use_cassette(:remove_user_permissions) do
69
+ response = client.remove_user_permissions(content_source_key, user, :permissions => permissions)
70
+ expect(response['permissions']).to eq([])
71
+ end
72
+ end
73
+ end
74
+
75
+ end