recombee_api_client 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -4
  3. data/lib/recombee_api_client.rb +55 -36
  4. data/lib/recombee_api_client/api/add_bookmark.rb +2 -0
  5. data/lib/recombee_api_client/api/add_cart_addition.rb +2 -0
  6. data/lib/recombee_api_client/api/add_detail_view.rb +2 -0
  7. data/lib/recombee_api_client/api/add_group.rb +2 -0
  8. data/lib/recombee_api_client/api/add_item.rb +2 -0
  9. data/lib/recombee_api_client/api/add_item_property.rb +2 -0
  10. data/lib/recombee_api_client/api/add_purchase.rb +2 -0
  11. data/lib/recombee_api_client/api/add_rating.rb +2 -0
  12. data/lib/recombee_api_client/api/add_series.rb +2 -0
  13. data/lib/recombee_api_client/api/add_user.rb +2 -0
  14. data/lib/recombee_api_client/api/batch.rb +2 -0
  15. data/lib/recombee_api_client/api/delete_bookmark.rb +17 -5
  16. data/lib/recombee_api_client/api/delete_cart_addition.rb +17 -5
  17. data/lib/recombee_api_client/api/delete_detail_view.rb +17 -5
  18. data/lib/recombee_api_client/api/delete_group.rb +2 -0
  19. data/lib/recombee_api_client/api/delete_item.rb +2 -0
  20. data/lib/recombee_api_client/api/delete_item_property.rb +2 -0
  21. data/lib/recombee_api_client/api/delete_purchase.rb +17 -5
  22. data/lib/recombee_api_client/api/delete_rating.rb +17 -5
  23. data/lib/recombee_api_client/api/delete_series.rb +2 -0
  24. data/lib/recombee_api_client/api/delete_user.rb +2 -0
  25. data/lib/recombee_api_client/api/get_item_property_info.rb +2 -0
  26. data/lib/recombee_api_client/api/get_item_values.rb +2 -0
  27. data/lib/recombee_api_client/api/insert_to_group.rb +2 -0
  28. data/lib/recombee_api_client/api/insert_to_series.rb +2 -0
  29. data/lib/recombee_api_client/api/item_based_recommendation.rb +19 -3
  30. data/lib/recombee_api_client/api/list_group_items.rb +2 -0
  31. data/lib/recombee_api_client/api/list_groups.rb +2 -0
  32. data/lib/recombee_api_client/api/list_item_bookmarks.rb +2 -0
  33. data/lib/recombee_api_client/api/list_item_cart_additions.rb +2 -0
  34. data/lib/recombee_api_client/api/list_item_detail_views.rb +2 -0
  35. data/lib/recombee_api_client/api/list_item_properties.rb +2 -0
  36. data/lib/recombee_api_client/api/list_item_purchases.rb +2 -0
  37. data/lib/recombee_api_client/api/list_item_ratings.rb +2 -0
  38. data/lib/recombee_api_client/api/list_items.rb +2 -0
  39. data/lib/recombee_api_client/api/list_series.rb +2 -0
  40. data/lib/recombee_api_client/api/list_series_items.rb +2 -0
  41. data/lib/recombee_api_client/api/list_user_bookmarks.rb +2 -0
  42. data/lib/recombee_api_client/api/list_user_cart_additions.rb +2 -0
  43. data/lib/recombee_api_client/api/list_user_detail_views.rb +2 -0
  44. data/lib/recombee_api_client/api/list_user_purchases.rb +2 -0
  45. data/lib/recombee_api_client/api/list_user_ratings.rb +2 -0
  46. data/lib/recombee_api_client/api/list_users.rb +2 -0
  47. data/lib/recombee_api_client/api/merge_users.rb +2 -0
  48. data/lib/recombee_api_client/api/remove_from_group.rb +2 -0
  49. data/lib/recombee_api_client/api/remove_from_series.rb +2 -0
  50. data/lib/recombee_api_client/api/reset_database.rb +3 -1
  51. data/lib/recombee_api_client/api/set_item_values.rb +2 -0
  52. data/lib/recombee_api_client/api/user_based_recommendation.rb +19 -3
  53. data/lib/recombee_api_client/version.rb +1 -1
  54. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 502d27b927763c5c54e373aca3db137df0198683
4
- data.tar.gz: 0dea5323ad9a5b304bd72a8fe20f590ce8002103
3
+ metadata.gz: 11704e7192a3cf0b6f8122a3049608247b5c274f
4
+ data.tar.gz: 1841fd3587cde54649877aaf150f798649264072
5
5
  SHA512:
6
- metadata.gz: 2787a7a249bf23cb1df46cb9047c6e36e13227677a936c79a87a680547c21829850de8ec2c3dda9083dd9351abd35c3fbdea0d0607da93dae85669138ff6c151
7
- data.tar.gz: 117af7984b724ada34b5ffac9bbf03e3efbded675733daf76e7ceb79a25b494db5285c8408a33c089f68117940879030cdac28d6e1a53714b627a0324c65734a
6
+ metadata.gz: 5f61d16bcb1bd799376ba4e4c984ab806960bb14ccd3f7c2c22754bdcdcc4228107873a72a88c15a1f186be7f19e256a38041fe72392778be5a452e26589e97d
7
+ data.tar.gz: 21109e33ba9b98f43a62b512c825420c4f1e1544f067b109a1195386785d488365229f94bcf618d271a0b3992dafe15e188c885e5389cd42c7f6653e9cf2ba81
data/README.md CHANGED
@@ -49,7 +49,7 @@ begin
49
49
  puts 'Send items'
50
50
  client.send(Batch.new(my_items.map { |itemId| AddItem.new(itemId) }))
51
51
  puts 'Send purchases'
52
- client.send(Batch.new(my_purchases.map { |p| AddPurchase.new(p['userId'], p['itemId'], 0) }))
52
+ client.send(Batch.new(my_purchases.map { |p| AddPurchase.new(p['userId'], p['itemId']) }))
53
53
 
54
54
  # Get recommendations for user 'user-25'
55
55
  puts 'Recommend for a user'
@@ -62,8 +62,6 @@ end
62
62
 
63
63
  ### Using property values
64
64
  ```ruby
65
- #!/usr/bin/env ruby
66
-
67
65
  require 'recombee_api_client'
68
66
  include RecombeeApiClient
69
67
 
@@ -107,7 +105,7 @@ requests = []
107
105
  user_ids = (1..NUM).map{|i| "user-#{i}"}
108
106
  user_ids = user_ids.select { |_| rand(0.0..1.0) < PROBABILITY_PURCHASED }
109
107
  # Use cascadeCreate to create unexisting users
110
- user_ids.each { |user_id| requests.push(AddPurchase.new(user_id, item_id, 0, 'cascadeCreate' => true)) }
108
+ user_ids.each { |user_id| requests.push(AddPurchase.new(user_id, item_id, 'cascadeCreate' => true)) }
111
109
  end
112
110
 
113
111
  # Send purchases to the recommender system
@@ -1,6 +1,6 @@
1
1
  require 'recombee_api_client/version'
2
2
  require 'securerandom'
3
- require 'digest/hmac'
3
+ require 'openssl'
4
4
  require 'httparty'
5
5
  require 'json'
6
6
  require 'open-uri'
@@ -11,85 +11,103 @@ require 'recombee_api_client/errors'
11
11
  Gem.find_files('recombee_api_client/api/*.rb').each { |path| require path }
12
12
 
13
13
  module RecombeeApiClient
14
+ ##
15
+ # Client for sending requests to Recombee recommender system
14
16
  class RecombeeClient
15
17
  include HTTParty
16
18
 
17
- def initialize(account, token, options = {})
19
+ ##
20
+ # - +account+ -> Name of your account at Recombee
21
+ # - +token+ -> Secret token obtained from Recombee for signing requests
22
+ # - +protocol+ -> Default protocol for sending requests. Possible values: 'http', 'https'.
23
+ def initialize(account, token, protocol = 'http', options = {})
18
24
  @account = account
19
25
  @token = token
20
- @base_uri = options[:base_uri] ||= 'https://rapi.recombee.com'
26
+ @protocol = protocol
27
+ @base_uri = ENV['RAPI_URI'] if ENV.key? 'RAPI_URI'
28
+ @base_uri||= options[:base_uri]
29
+ @base_uri||= 'rapi.recombee.com'
21
30
  end
22
31
 
32
+ ##
33
+ # - +request+ -> ApiRequest to be sent to Recombee recommender
23
34
  def send(request)
24
- @request = request
25
- uri = request.path
26
- uri.slice! ('/{databaseId}/')
27
- uri = URI.escape uri
28
35
  timeout = request.timeout / 1000
36
+ uri = process_request_uri(request)
37
+ uri = sign_url(uri)
38
+ protocol = request.ensure_https ? 'https' : @protocol
39
+ uri = protocol + '://' + @base_uri + uri
29
40
  # puts uri
30
41
  begin
31
42
  case request.method
32
43
  when :put
33
- hmac_put(uri, timeout)
44
+ put(request, uri, timeout)
34
45
  when :get
35
- hmac_get(uri, timeout)
46
+ get(request, uri, timeout)
36
47
  when :post
37
- hmac_post(uri, timeout, request.body_parameters.to_json)
48
+ post(request, uri, timeout)
38
49
  when :delete
39
- hmac_delete(uri, timeout)
50
+ delete(request, uri, timeout)
40
51
  end
41
52
  rescue Timeout::Error
42
- fail ApiTimeout.new(@request)
53
+ fail ApiTimeout.new(request)
43
54
  end
44
55
  end
45
56
 
46
57
  private
47
58
 
48
- def hmac_put(uri, timeout, options = {})
49
- r = self.class.put(sign_url(uri), query: options, timeout: timeout)
50
- check_errors r
51
- r.body
59
+ def put(request, uri, timeout)
60
+ response = self.class.put(uri, timeout: timeout)
61
+ check_errors(response, request)
62
+ response.body
52
63
  end
53
64
 
54
- def hmac_get(uri, timeout, options = {})
55
- r = self.class.get(sign_url(uri), query: options, timeout: timeout)
56
- check_errors r
57
- JSON.parse(r.body)
65
+ def get(request, uri, timeout)
66
+ response = self.class.get(uri, timeout: timeout)
67
+ check_errors(response, request)
68
+ JSON.parse(response.body)
58
69
  end
59
70
 
60
- def hmac_post(uri, timeout, options = {})
61
- url = sign_url(uri)
71
+ def post(request, uri, timeout)
62
72
  # pass arguments in body
63
- r = self.class.post(url, body: options,
73
+ response = self.class.post(uri, body: request.body_parameters.to_json,
64
74
  headers: { 'Content-Type' => 'application/json' },
65
75
  timeout: timeout)
66
- check_errors r
76
+ check_errors(response, request)
67
77
  begin
68
- return JSON.parse(r.body)
78
+ return JSON.parse(response.body)
69
79
  rescue JSON::ParserError
70
- return r.body
80
+ return response.body
71
81
  end
72
82
  end
73
83
 
74
- def hmac_delete(uri, timeout, options = {})
75
- r = self.class.delete(sign_url(uri), query: options, timeout: timeout)
76
- check_errors r
77
- r.body
84
+ def delete(request, uri, timeout)
85
+ response = self.class.delete(uri, timeout: timeout)
86
+ check_errors(response, request)
87
+ response.body
78
88
  end
79
89
 
80
- def check_errors(response)
90
+ def check_errors(response, request)
81
91
  status_code = response.code
82
92
  return if status_code == 200 || status_code == 201
83
- fail ResponseError.new(@request, status_code, response.body)
93
+ fail ResponseError.new(request, status_code, response.body)
94
+ end
95
+
96
+ def process_request_uri(request)
97
+ uri = request.path
98
+ uri.slice! ('/{databaseId}/')
99
+ uri = URI.escape uri
100
+ uri
84
101
  end
85
102
 
86
103
  # Sign request with HMAC, request URI must be exacly the same
87
104
  # We have 30s to complete request with this token
88
- def sign_url(req)
89
- uri = "/#{@account}/#{req}"
105
+ def sign_url(req_part)
106
+ uri = "/#{@account}/#{req_part}"
90
107
  time = hmac_time(uri)
91
108
  sign = hmac_sign(uri, time)
92
- @base_uri + uri + time + "&hmac_sign=#{sign}"
109
+ res = uri + time + "&hmac_sign=#{sign}"
110
+ res
93
111
  end
94
112
 
95
113
  def hmac_time(uri)
@@ -99,7 +117,8 @@ module RecombeeApiClient
99
117
 
100
118
  def hmac_sign(uri, time)
101
119
  url = uri + time
102
- Digest::HMAC.hexdigest(url, @token, Digest::SHA1)
120
+ digest = OpenSSL::Digest.new('sha1')
121
+ OpenSSL::HMAC.hexdigest(digest, @token, url)
103
122
  end
104
123
  end
105
124
  end
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddBookmark < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp, :cascade_create
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -29,6 +30,7 @@ module RecombeeApiClient
29
30
  @cascade_create = optional['cascadeCreate']
30
31
  @optional = optional
31
32
  @timeout = 1000
33
+ @ensure_https = false
32
34
  @optional.each do |par, _|
33
35
  fail UnknownOptionalParameter.new(par) unless ["timestamp","cascadeCreate"].include? par
34
36
  end
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddCartAddition < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp, :cascade_create
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -29,6 +30,7 @@ module RecombeeApiClient
29
30
  @cascade_create = optional['cascadeCreate']
30
31
  @optional = optional
31
32
  @timeout = 1000
33
+ @ensure_https = false
32
34
  @optional.each do |par, _|
33
35
  fail UnknownOptionalParameter.new(par) unless ["timestamp","cascadeCreate"].include? par
34
36
  end
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddDetailView < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp, :duration, :cascade_create
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -31,6 +32,7 @@ module RecombeeApiClient
31
32
  @cascade_create = optional['cascadeCreate']
32
33
  @optional = optional
33
34
  @timeout = 1000
35
+ @ensure_https = false
34
36
  @optional.each do |par, _|
35
37
  fail UnknownOptionalParameter.new(par) unless ["timestamp","duration","cascadeCreate"].include? par
36
38
  end
@@ -11,6 +11,7 @@ module RecombeeApiClient
11
11
  class AddGroup < ApiRequest
12
12
  attr_reader :group_id
13
13
  attr_accessor :timeout
14
+ attr_accessor :ensure_https
14
15
 
15
16
  ##
16
17
  # * *Required arguments*
@@ -19,6 +20,7 @@ module RecombeeApiClient
19
20
  def initialize(group_id)
20
21
  @group_id = group_id
21
22
  @timeout = 1000
23
+ @ensure_https = false
22
24
  end
23
25
 
24
26
  # HTTP method
@@ -14,6 +14,7 @@ module RecombeeApiClient
14
14
  class AddItem < ApiRequest
15
15
  attr_reader :item_id
16
16
  attr_accessor :timeout
17
+ attr_accessor :ensure_https
17
18
 
18
19
  ##
19
20
  # * *Required arguments*
@@ -22,6 +23,7 @@ module RecombeeApiClient
22
23
  def initialize(item_id)
23
24
  @item_id = item_id
24
25
  @timeout = 1000
26
+ @ensure_https = false
25
27
  end
26
28
 
27
29
  # HTTP method
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddItemProperty < ApiRequest
13
13
  attr_reader :property_name, :type
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -24,6 +25,7 @@ module RecombeeApiClient
24
25
  @property_name = property_name
25
26
  @type = type
26
27
  @timeout = 1000
28
+ @ensure_https = false
27
29
  end
28
30
 
29
31
  # HTTP method
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddPurchase < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp, :cascade_create
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -29,6 +30,7 @@ module RecombeeApiClient
29
30
  @cascade_create = optional['cascadeCreate']
30
31
  @optional = optional
31
32
  @timeout = 1000
33
+ @ensure_https = false
32
34
  @optional.each do |par, _|
33
35
  fail UnknownOptionalParameter.new(par) unless ["timestamp","cascadeCreate"].include? par
34
36
  end
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddRating < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp, :rating, :cascade_create
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -31,6 +32,7 @@ module RecombeeApiClient
31
32
  @cascade_create = optional['cascadeCreate']
32
33
  @optional = optional
33
34
  @timeout = 1000
35
+ @ensure_https = false
34
36
  @optional.each do |par, _|
35
37
  fail UnknownOptionalParameter.new(par) unless ["timestamp","cascadeCreate"].include? par
36
38
  end
@@ -11,6 +11,7 @@ module RecombeeApiClient
11
11
  class AddSeries < ApiRequest
12
12
  attr_reader :series_id
13
13
  attr_accessor :timeout
14
+ attr_accessor :ensure_https
14
15
 
15
16
  ##
16
17
  # * *Required arguments*
@@ -19,6 +20,7 @@ module RecombeeApiClient
19
20
  def initialize(series_id)
20
21
  @series_id = series_id
21
22
  @timeout = 1000
23
+ @ensure_https = false
22
24
  end
23
25
 
24
26
  # HTTP method
@@ -12,6 +12,7 @@ module RecombeeApiClient
12
12
  class AddUser < ApiRequest
13
13
  attr_reader :user_id
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
@@ -20,6 +21,7 @@ module RecombeeApiClient
20
21
  def initialize(user_id)
21
22
  @user_id = user_id
22
23
  @timeout = 1000
24
+ @ensure_https = false
23
25
  end
24
26
 
25
27
  # HTTP method
@@ -9,6 +9,7 @@ module RecombeeApiClient
9
9
  class Batch < ApiRequest
10
10
  attr_reader :requests
11
11
  attr_accessor :timeout
12
+ attr_accessor :ensure_https
12
13
  ##
13
14
  # * *Required arguments*
14
15
  # - +requests+ -> Array of API requests.
@@ -17,6 +18,7 @@ module RecombeeApiClient
17
18
  @requests = requests
18
19
  @body_parameters = requests_to_batch_hash
19
20
  @timeout = requests.map{|r| r.timeout}.reduce(:+)
21
+ @ensure_https = true
20
22
  end
21
23
 
22
24
  # HTTP method
@@ -12,18 +12,26 @@ module RecombeeApiClient
12
12
  class DeleteBookmark < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
18
19
  # - +user_id+ -> ID of the user who made the bookmark.
19
20
  # - +item_id+ -> ID of the item of which was bookmarked.
20
- # - +timestamp+ -> Unix timestamp of the bookmark.
21
21
  #
22
- def initialize(user_id, item_id, timestamp)
22
+ # * *Optional arguments (given as hash optional)*
23
+ # - +timestamp+ -> Unix timestamp of the bookmark. If the `timestamp` is omitted, then all the bookmarks with given `userId` and `itemId` are deleted.
24
+ #
25
+ def initialize(user_id, item_id, optional = {})
23
26
  @user_id = user_id
24
27
  @item_id = item_id
25
- @timestamp = timestamp
28
+ @timestamp = optional['timestamp']
29
+ @optional = optional
26
30
  @timeout = 1000
31
+ @ensure_https = false
32
+ @optional.each do |par, _|
33
+ fail UnknownOptionalParameter.new(par) unless ["timestamp"].include? par
34
+ end
27
35
  end
28
36
 
29
37
  # HTTP method
@@ -43,7 +51,7 @@ module RecombeeApiClient
43
51
  params = {}
44
52
  params['userId'] = @user_id
45
53
  params['itemId'] = @item_id
46
- params['timestamp'] = @timestamp
54
+ params['timestamp'] = @optional['timestamp'] if @optional['timestamp']
47
55
  params
48
56
  end
49
57
 
@@ -54,7 +62,11 @@ module RecombeeApiClient
54
62
 
55
63
  # Relative path to the endpoint including query parameters
56
64
  def path
57
- p = "/{databaseId}/bookmarks/?userId=#{@user_id}&itemId=#{@item_id}&timestamp=#{@timestamp}"
65
+ p = "/{databaseId}/bookmarks/?userId=#{@user_id}&itemId=#{@item_id}"
66
+ if @optional.include? 'timestamp'
67
+ p += (p.include? '?') ? '&' : '?'
68
+ p += "timestamp=#{@optional['timestamp']}"
69
+ end
58
70
  p
59
71
  end
60
72
  end
@@ -12,18 +12,26 @@ module RecombeeApiClient
12
12
  class DeleteCartAddition < ApiRequest
13
13
  attr_reader :user_id, :item_id, :timestamp
14
14
  attr_accessor :timeout
15
+ attr_accessor :ensure_https
15
16
 
16
17
  ##
17
18
  # * *Required arguments*
18
19
  # - +user_id+ -> ID of the user who made the cart addition.
19
20
  # - +item_id+ -> ID of the item of which was added to cart.
20
- # - +timestamp+ -> Unix timestamp of the cart addition.
21
21
  #
22
- def initialize(user_id, item_id, timestamp)
22
+ # * *Optional arguments (given as hash optional)*
23
+ # - +timestamp+ -> Unix timestamp of the cart addition. If the `timestamp` is omitted, then all the cart additions with given `userId` and `itemId` are deleted.
24
+ #
25
+ def initialize(user_id, item_id, optional = {})
23
26
  @user_id = user_id
24
27
  @item_id = item_id
25
- @timestamp = timestamp
28
+ @timestamp = optional['timestamp']
29
+ @optional = optional
26
30
  @timeout = 1000
31
+ @ensure_https = false
32
+ @optional.each do |par, _|
33
+ fail UnknownOptionalParameter.new(par) unless ["timestamp"].include? par
34
+ end
27
35
  end
28
36
 
29
37
  # HTTP method
@@ -43,7 +51,7 @@ module RecombeeApiClient
43
51
  params = {}
44
52
  params['userId'] = @user_id
45
53
  params['itemId'] = @item_id
46
- params['timestamp'] = @timestamp
54
+ params['timestamp'] = @optional['timestamp'] if @optional['timestamp']
47
55
  params
48
56
  end
49
57
 
@@ -54,7 +62,11 @@ module RecombeeApiClient
54
62
 
55
63
  # Relative path to the endpoint including query parameters
56
64
  def path
57
- p = "/{databaseId}/cartadditions/?userId=#{@user_id}&itemId=#{@item_id}&timestamp=#{@timestamp}"
65
+ p = "/{databaseId}/cartadditions/?userId=#{@user_id}&itemId=#{@item_id}"
66
+ if @optional.include? 'timestamp'
67
+ p += (p.include? '?') ? '&' : '?'
68
+ p += "timestamp=#{@optional['timestamp']}"
69
+ end
58
70
  p
59
71
  end
60
72
  end