meilisearch 0.18.0 → 0.18.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: df541b398ac4b031ec615d5e20c6a19cd7c370cdeaf83dcf63d789374827f012
4
- data.tar.gz: 9277554fe2d6f388491d506cbfda456e71a1cc90b1945d933cfa72a2147ee52c
3
+ metadata.gz: f9ffb59831da7243cc87f65a0cd0a0d11d311e4691fd1177779fae006f4a750d
4
+ data.tar.gz: 04cd78aa37677107d08a355daa016d72d8be0d2980d1da27f1e5102dde45c661
5
5
  SHA512:
6
- metadata.gz: bc0446c08444d6bf48d796c62c9b92e5f008835463b08c916e52f0ac9ce81156bcb835cd645fd78c31b98907a06230cf60fe2dbcfdcf0102b9c3fe8f9dfc2732
7
- data.tar.gz: ac4f2136062699556c365e296db97fe54c6085a228c2b6831b963a72557918c100b83f7e5241183b5d9d173927e127b1e2ad402045dc64ec71056c7b57663fb2
6
+ metadata.gz: 1b7cc2bcb9f6c228397ca5cceaa9ad76c0fb3e522f29ea2231ac9a304c762fdc1cc2eda55deaeead572d5b8ab0468681db57b8fe6b28ee078a96324894a54a1c
7
+ data.tar.gz: 551fc3177689b479102a2f23329ca7243ae768ba13d7ddeea48e09f531c8305fcd43207e5f20e9b3d28bf5e0c88d7e6ae5247ea115213abc890264369785fbfd
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2019-2021 Meili
3
+ Copyright (c) 2019-2022 Meili SAS
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  <p align="center">
2
- <img src="https://res.cloudinary.com/meilisearch/image/upload/v1587402338/SDKs/meilisearch_ruby.svg" alt="MeiliSearch-Ruby" width="200" height="200" />
2
+ <img src="https://raw.githubusercontent.com/meilisearch/integration-guides/main/assets/logos/meilisearch_ruby.svg" alt="Meilisearch-Ruby" width="200" height="200" />
3
3
  </p>
4
4
 
5
- <h1 align="center">MeiliSearch Ruby</h1>
5
+ <h1 align="center">Meilisearch Ruby</h1>
6
6
 
7
7
  <h4 align="center">
8
- <a href="https://github.com/meilisearch/MeiliSearch">MeiliSearch</a> |
8
+ <a href="https://github.com/meilisearch/meilisearch">Meilisearch</a> |
9
9
  <a href="https://docs.meilisearch.com">Documentation</a> |
10
10
  <a href="https://slack.meilisearch.com">Slack</a> |
11
11
  <a href="https://roadmap.meilisearch.com/tabs/1-under-consideration">Roadmap</a> |
@@ -20,18 +20,18 @@
20
20
  <a href="https://ms-bors.herokuapp.com/repositories/6"><img src="https://bors.tech/images/badge_small.svg" alt="Bors enabled"></a>
21
21
  </p>
22
22
 
23
- <p align="center">⚡ The MeiliSearch API client written for Ruby 💎</p>
23
+ <p align="center">⚡ The Meilisearch API client written for Ruby 💎</p>
24
24
 
25
- **MeiliSearch Ruby** is the MeiliSearch API client for Ruby developers.
25
+ **Meilisearch Ruby** is the Meilisearch API client for Ruby developers.
26
26
 
27
- **MeiliSearch** is an open-source search engine. [Discover what MeiliSearch is!](https://github.com/meilisearch/MeiliSearch)
27
+ **Meilisearch** is an open-source search engine. [Discover what Meilisearch is!](https://github.com/meilisearch/meilisearch)
28
28
 
29
29
  ## Table of Contents <!-- omit in toc -->
30
30
 
31
31
  - [📖 Documentation](#-documentation)
32
32
  - [🔧 Installation](#-installation)
33
33
  - [🚀 Getting Started](#-getting-started)
34
- - [🤖 Compatibility with MeiliSearch](#-compatibility-with-meilisearch)
34
+ - [🤖 Compatibility with Meilisearch](#-compatibility-with-meilisearch)
35
35
  - [💡 Learn More](#-learn-more)
36
36
  - [⚙️ Development Workflow and Contributing](#️-development-workflow-and-contributing)
37
37
 
@@ -55,21 +55,21 @@ source 'https://rubygems.org'
55
55
  gem 'meilisearch'
56
56
  ```
57
57
 
58
- ### Run MeiliSearch <!-- omit in toc -->
58
+ ### Run Meilisearch <!-- omit in toc -->
59
59
 
60
- There are many easy ways to [download and run a MeiliSearch instance](https://docs.meilisearch.com/reference/features/installation.html#download-and-launch).
60
+ There are many easy ways to [download and run a Meilisearch instance](https://docs.meilisearch.com/reference/features/installation.html#download-and-launch).
61
61
 
62
62
  For example, using the `curl` command in your [Terminal](https://itconnect.uw.edu/learn/workshops/online-tutorials/web-publishing/what-is-a-terminal/):
63
63
 
64
64
  ```sh
65
- #Install MeiliSearch
65
+ #Install Meilisearch
66
66
  curl -L https://install.meilisearch.com | sh
67
67
 
68
- # Launch MeiliSearch
68
+ # Launch Meilisearch
69
69
  ./meilisearch --master-key=masterKey
70
70
  ```
71
71
 
72
- NB: you can also download MeiliSearch from **Homebrew** or **APT** or even run it using **Docker**.
72
+ NB: you can also download Meilisearch from **Homebrew** or **APT** or even run it using **Docker**.
73
73
 
74
74
  ## 🚀 Getting Started
75
75
 
@@ -91,7 +91,7 @@ documents = [
91
91
  { id: 5, title: 'Moana', genres: ['Fantasy', 'Action']},
92
92
  { id: 6, title: 'Philadelphia', genres: ['Drama'] },
93
93
  ]
94
- # If the index 'movies' does not exist, MeiliSearch creates it when you first add the documents.
94
+ # If the index 'movies' does not exist, Meilisearch creates it when you first add the documents.
95
95
  index.add_documents(documents) # => { "uid": 0 }
96
96
  ```
97
97
 
@@ -102,7 +102,7 @@ With the `uid`, you can check the status (`enqueued`, `processing`, `succeeded`
102
102
  #### Basic Search <!-- omit in toc -->
103
103
 
104
104
  ``` ruby
105
- # MeiliSearch is typo-tolerant:
105
+ # Meilisearch is typo-tolerant:
106
106
  puts index.search('carlo')
107
107
  ```
108
108
  Output:
@@ -165,7 +165,7 @@ index.update_filterable_attributes([
165
165
 
166
166
  You only need to perform this operation once.
167
167
 
168
- Note that MeiliSearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [tasks](https://docs.meilisearch.com/reference/api/tasks.html#get-task)).
168
+ Note that Meilisearch will rebuild your index whenever you update `filterableAttributes`. Depending on the size of your dataset, this might take time. You can track the process using the [tasks](https://docs.meilisearch.com/reference/api/tasks.html#get-task)).
169
169
 
170
170
  Then, you can perform the search:
171
171
 
@@ -196,9 +196,9 @@ JSON output:
196
196
  }
197
197
  ```
198
198
 
199
- ## 🤖 Compatibility with MeiliSearch
199
+ ## 🤖 Compatibility with Meilisearch
200
200
 
201
- This package only guarantees the compatibility with the [version v0.25.0 of MeiliSearch](https://github.com/meilisearch/MeiliSearch/releases/tag/v0.25.0).
201
+ This package only guarantees the compatibility with the [version v0.27.0 of Meilisearch](https://github.com/meilisearch/meilisearch/releases/tag/v0.27.0).
202
202
 
203
203
  ## 💡 Learn More
204
204
 
@@ -219,4 +219,4 @@ If you want to know more about the development workflow or want to contribute, p
219
219
 
220
220
  <hr>
221
221
 
222
- **MeiliSearch** provides and maintains many **SDKs and Integration tools** like this one. We want to provide everyone with an **amazing search experience for any kind of project**. If you want to contribute, make suggestions, or just know what's going on right now, visit us in the [integration-guides](https://github.com/meilisearch/integration-guides) repository.
222
+ **Meilisearch** provides and maintains many **SDKs and Integration tools** like this one. We want to provide everyone with an **amazing search experience for any kind of project**. If you want to contribute, make suggestions, or just know what's going on right now, visit us in the [integration-guides](https://github.com/meilisearch/integration-guides) repository.
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'meilisearch/http_request'
4
-
5
3
  module MeiliSearch
6
4
  class Client < HTTPRequest
5
+ include MeiliSearch::TenantToken
6
+
7
7
  ### INDEXES
8
8
 
9
9
  def raw_indexes
@@ -57,9 +57,15 @@ module MeiliSearch
57
57
  class TimeoutError < StandardError
58
58
  attr_reader :message
59
59
 
60
- def initialize
61
- @message = 'The update was not processed in the expected time'
60
+ def initialize(message = nil)
61
+ @message = "The request was not processed in the expected time. #{message}"
62
62
  super(@message)
63
63
  end
64
64
  end
65
+
66
+ module TenantToken
67
+ class ExpireOrInvalidSignature < StandardError; end
68
+ class InvalidApiKey < StandardError; end
69
+ class InvalidSearchRules < StandardError; end
70
+ end
65
71
  end
@@ -7,25 +7,30 @@ module MeiliSearch
7
7
  class HTTPRequest
8
8
  include HTTParty
9
9
 
10
- attr_reader :options
10
+ attr_reader :options, :headers
11
+
12
+ DEFAULT_OPTIONS = {
13
+ timeout: 1,
14
+ max_retries: 0,
15
+ convert_body?: true
16
+ }.freeze
11
17
 
12
18
  def initialize(url, api_key = nil, options = {})
13
19
  @base_url = url
14
20
  @api_key = api_key
15
- @options = merge_options({
16
- timeout: 1,
17
- max_retries: 0,
18
- headers: build_default_options_headers(api_key),
19
- convert_body?: true
20
- }, options)
21
+ @options = DEFAULT_OPTIONS.merge(options)
22
+ @headers = build_default_options_headers
21
23
  end
22
24
 
23
25
  def http_get(relative_path = '', query_params = {})
24
26
  send_request(
25
27
  proc { |path, config| self.class.get(path, config) },
26
28
  relative_path,
27
- query_params: query_params,
28
- options: remove_options_header(@options, 'Content-Type')
29
+ config: {
30
+ query_params: query_params,
31
+ headers: remove_headers(@headers.dup, 'Content-Type'),
32
+ options: @options
33
+ }
29
34
  )
30
35
  end
31
36
 
@@ -33,9 +38,12 @@ module MeiliSearch
33
38
  send_request(
34
39
  proc { |path, config| self.class.post(path, config) },
35
40
  relative_path,
36
- query_params: query_params,
37
- body: body,
38
- options: merge_options(@options, options)
41
+ config: {
42
+ query_params: query_params,
43
+ body: body,
44
+ headers: @headers.dup.merge(options[:headers] || {}),
45
+ options: @options.merge(options)
46
+ }
39
47
  )
40
48
  end
41
49
 
@@ -43,9 +51,12 @@ module MeiliSearch
43
51
  send_request(
44
52
  proc { |path, config| self.class.put(path, config) },
45
53
  relative_path,
46
- query_params: query_params,
47
- body: body,
48
- options: @options
54
+ config: {
55
+ query_params: query_params,
56
+ body: body,
57
+ headers: @headers,
58
+ options: @options
59
+ }
49
60
  )
50
61
  end
51
62
 
@@ -53,9 +64,12 @@ module MeiliSearch
53
64
  send_request(
54
65
  proc { |path, config| self.class.patch(path, config) },
55
66
  relative_path,
56
- query_params: query_params,
57
- body: body,
58
- options: @options
67
+ config: {
68
+ query_params: query_params,
69
+ body: body,
70
+ headers: @headers,
71
+ options: @options
72
+ }
59
73
  )
60
74
  end
61
75
 
@@ -63,53 +77,45 @@ module MeiliSearch
63
77
  send_request(
64
78
  proc { |path, config| self.class.delete(path, config) },
65
79
  relative_path,
66
- options: remove_options_header(@options, 'Content-Type')
80
+ config: {
81
+ headers: remove_headers(@headers.dup, 'Content-Type'),
82
+ options: @options
83
+ }
67
84
  )
68
85
  end
69
86
 
70
87
  private
71
88
 
72
- def build_default_options_headers(api_key = nil)
73
- header = {
74
- 'Content-Type' => 'application/json'
75
- }
76
- header = header.merge('Authorization' => "Bearer #{api_key}") unless api_key.nil?
77
- header
78
- end
79
-
80
- def merge_options(default_options, added_options = {})
81
- default_cloned_headers = default_options[:headers].clone
82
- merged_options = default_options.merge(added_options)
83
- merged_options[:headers] = default_cloned_headers.merge(added_options[:headers]) if added_options.key?(:headers)
84
- merged_options
89
+ def build_default_options_headers
90
+ {
91
+ 'Content-Type' => 'application/json',
92
+ 'Authorization' => ("Bearer #{@api_key}" unless @api_key.nil?),
93
+ 'User-Agent' => MeiliSearch.qualified_version
94
+ }.compact
85
95
  end
86
96
 
87
- def remove_options_header(options, key)
88
- cloned_options = clone_options(options)
89
- cloned_options[:headers].tap { |headers| headers.delete(key) }
90
- cloned_options
97
+ def remove_headers(data, *keys)
98
+ data.delete_if { |k| keys.include?(k) }
91
99
  end
92
100
 
93
- def clone_options(options)
94
- cloned_options = options.clone
95
- cloned_options[:headers] = options[:headers].clone
96
- cloned_options
97
- end
101
+ def send_request(http_method, relative_path, config: {})
102
+ config = http_config(config[:query_params], config[:body], config[:options], config[:headers])
98
103
 
99
- def send_request(http_method, relative_path, query_params: nil, body: nil, options: {})
100
- config = http_config(query_params, body, options)
101
104
  begin
102
105
  response = http_method.call(@base_url + relative_path, config)
103
- rescue Errno::ECONNREFUSED => e
106
+ rescue Errno::ECONNREFUSED, Errno::EPIPE => e
104
107
  raise CommunicationError, e.message
108
+ rescue Net::ReadTimeout, Net::OpenTimeout => e
109
+ raise TimeoutError, e.message
105
110
  end
111
+
106
112
  validate(response)
107
113
  end
108
114
 
109
- def http_config(query_params, body, options)
115
+ def http_config(query_params, body, options, headers)
110
116
  body = body.to_json if options[:convert_body?] == true
111
117
  {
112
- headers: options[:headers],
118
+ headers: headers,
113
119
  query: query_params,
114
120
  body: body,
115
121
  timeout: options[:timeout],
@@ -81,7 +81,7 @@ module MeiliSearch
81
81
  alias add_or_replace_documents! add_documents!
82
82
 
83
83
  def add_documents_json(documents, primary_key = nil)
84
- options = { headers: { 'Content-Type' => 'application/json' }, convert_body?: false }
84
+ options = { convert_body?: false }
85
85
  http_post "/indexes/#{@uid}/documents", documents, { primaryKey: primary_key }.compact, options
86
86
  end
87
87
  alias replace_documents_json add_documents_json
@@ -0,0 +1,70 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MeiliSearch
4
+ module TenantToken
5
+ HEADER = {
6
+ typ: 'JWT',
7
+ alg: 'HS256'
8
+ }.freeze
9
+
10
+ def generate_tenant_token(search_rules, api_key: nil, expires_at: nil)
11
+ signature = retrieve_valid_key!(api_key, @api_key)
12
+ expiration = validate_expires_at!(expires_at)
13
+ rules = validate_search_rules!(search_rules)
14
+ unsigned_data = build_payload(expiration, rules, signature)
15
+
16
+ combine(unsigned_data, to_base64(sign_data(signature, unsigned_data)))
17
+ end
18
+
19
+ private
20
+
21
+ def build_payload(expiration, rules, signature)
22
+ payload = {
23
+ searchRules: rules,
24
+ apiKeyPrefix: signature[0..7],
25
+ exp: expiration
26
+ }
27
+
28
+ combine(encode(HEADER), encode(payload))
29
+ end
30
+
31
+ def validate_expires_at!(expires_at)
32
+ return unless expires_at
33
+ return expires_at.to_i if expires_at.utc? && expires_at > Time.now.utc
34
+
35
+ raise
36
+ rescue StandardError
37
+ raise ExpireOrInvalidSignature
38
+ end
39
+
40
+ def validate_search_rules!(data)
41
+ return data if data
42
+
43
+ raise InvalidSearchRules
44
+ end
45
+
46
+ def retrieve_valid_key!(*keys)
47
+ key = keys.compact.find { |k| !k.empty? }
48
+
49
+ raise InvalidApiKey if key.nil?
50
+
51
+ key
52
+ end
53
+
54
+ def sign_data(key, msg)
55
+ OpenSSL::HMAC.digest('SHA256', key, msg)
56
+ end
57
+
58
+ def to_base64(data)
59
+ Base64.urlsafe_encode64(data, padding: false)
60
+ end
61
+
62
+ def encode(data)
63
+ to_base64(JSON.generate(data))
64
+ end
65
+
66
+ def combine(*parts)
67
+ parts.join('.')
68
+ end
69
+ end
70
+ end
@@ -1,5 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MeiliSearch
4
- VERSION = '0.18.0'
4
+ VERSION = '0.18.3'
5
+
6
+ def self.qualified_version
7
+ "Meilisearch Ruby (v#{VERSION})"
8
+ end
5
9
  end
data/lib/meilisearch.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require 'meilisearch/version'
4
4
  require 'meilisearch/utils'
5
+ require 'meilisearch/http_request'
6
+ require 'meilisearch/tenant_token'
5
7
  require 'meilisearch/task'
6
8
  require 'meilisearch/client'
7
9
  require 'meilisearch/index'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: meilisearch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.18.0
4
+ version: 0.18.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Meili
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-12 00:00:00.000000000 Z
11
+ date: 2022-05-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -30,7 +30,7 @@ dependencies:
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
32
  version: 0.21.0
33
- description: An easy-to-use ruby client for Meilisearch API. See https://github.com/meilisearch/MeiliSearch
33
+ description: An easy-to-use ruby client for Meilisearch API. See https://github.com/meilisearch/meilisearch
34
34
  email: bonjour@meilisearch.com
35
35
  executables: []
36
36
  extensions: []
@@ -44,6 +44,7 @@ files:
44
44
  - lib/meilisearch/http_request.rb
45
45
  - lib/meilisearch/index.rb
46
46
  - lib/meilisearch/task.rb
47
+ - lib/meilisearch/tenant_token.rb
47
48
  - lib/meilisearch/utils.rb
48
49
  - lib/meilisearch/version.rb
49
50
  homepage: https://github.com/meilisearch/meilisearch-ruby