supplejack_client 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +27 -0
- data/.rspec +2 -0
- data/Gemfile +16 -0
- data/Guardfile +24 -0
- data/LICENSE.txt +674 -0
- data/README.md +153 -0
- data/Rakefile +9 -0
- data/lib/generators/locales/en.yml +11 -0
- data/lib/generators/supplejack/install_generator.rb +28 -0
- data/lib/generators/templates/README +19 -0
- data/lib/generators/templates/supplejack_client.rb +120 -0
- data/lib/supplejack/config.rb +116 -0
- data/lib/supplejack/controllers/helpers.rb +172 -0
- data/lib/supplejack/engine.rb +20 -0
- data/lib/supplejack/exceptions.rb +17 -0
- data/lib/supplejack/facet.rb +33 -0
- data/lib/supplejack/item.rb +94 -0
- data/lib/supplejack/item_relation.rb +73 -0
- data/lib/supplejack/log_subscriber.rb +58 -0
- data/lib/supplejack/paginated_collection.rb +61 -0
- data/lib/supplejack/record.rb +147 -0
- data/lib/supplejack/request.rb +95 -0
- data/lib/supplejack/search.rb +346 -0
- data/lib/supplejack/url_formats/item_hash.rb +208 -0
- data/lib/supplejack/user.rb +132 -0
- data/lib/supplejack/user_set.rb +349 -0
- data/lib/supplejack/user_set_relation.rb +143 -0
- data/lib/supplejack/util.rb +120 -0
- data/lib/supplejack/version.rb +10 -0
- data/lib/supplejack_client.rb +29 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/supplejack/controllers/helpers_spec.rb +277 -0
- data/spec/supplejack/facet_spec.rb +44 -0
- data/spec/supplejack/item_relation_spec.rb +111 -0
- data/spec/supplejack/item_spec.rb +115 -0
- data/spec/supplejack/log_subscriber_spec.rb +40 -0
- data/spec/supplejack/paginated_collection_spec.rb +43 -0
- data/spec/supplejack/record_spec.rb +255 -0
- data/spec/supplejack/request_spec.rb +195 -0
- data/spec/supplejack/search_spec.rb +727 -0
- data/spec/supplejack/url_formats/item_hash_spec.rb +341 -0
- data/spec/supplejack/user_set_relation_spec.rb +149 -0
- data/spec/supplejack/user_set_spec.rb +465 -0
- data/spec/supplejack/user_spec.rb +159 -0
- data/supplejack_client.gemspec +30 -0
- metadata +159 -0
@@ -0,0 +1,208 @@
|
|
1
|
+
# The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
|
2
|
+
# and is licensed under the GNU General Public License, version 3.
|
3
|
+
# See https://github.com/DigitalNZ/supplejack_client for details.
|
4
|
+
#
|
5
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ
|
6
|
+
# and the Department of Internal Affairs. http://digitalnz.org/supplejack
|
7
|
+
|
8
|
+
module Supplejack
|
9
|
+
module UrlFormats
|
10
|
+
class ItemHash
|
11
|
+
|
12
|
+
attr_accessor :params, :search, :i_unlocked, :i_locked, :h_unlocked, :h_locked
|
13
|
+
|
14
|
+
def initialize(params={}, search=nil)
|
15
|
+
@params = params || {}
|
16
|
+
@search = search
|
17
|
+
@i_unlocked = filters_of_type(:i)
|
18
|
+
@i_locked = filters_of_type(:il)
|
19
|
+
@h_unlocked = filters_of_type(:h)
|
20
|
+
@h_locked = filters_of_type(:hl)
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_api_hash
|
24
|
+
hash = {}
|
25
|
+
text_value = text(params[:text])
|
26
|
+
hash[:text] = text_value if text_value
|
27
|
+
hash[:geo_bbox] = params[:geo_bbox] if params[:geo_bbox]
|
28
|
+
hash[:record_type] = params[:record_type] || 0
|
29
|
+
hash[:record_type] = hash[:record_type].to_i unless hash[:record_type]=="all"
|
30
|
+
hash[:page] = (params[:page] || 1).to_i
|
31
|
+
hash[:per_page] = (params[:per_page] || Supplejack.per_page).to_i
|
32
|
+
hash[:and] = and_filters if and_filters.try(:any?)
|
33
|
+
hash[:without] = without_filters if without_filters.try(:any?)
|
34
|
+
hash[:facets] = params[:facets] if params[:facets].present?
|
35
|
+
hash[:facets_per_page] = params[:facets_per_page].to_i if params[:facets_per_page].present?
|
36
|
+
hash[:fields] = params[:fields] || Supplejack.fields.join(',')
|
37
|
+
hash[:query_fields] = query_fields if query_fields
|
38
|
+
hash[:solr_query] = params[:solr_query] if params[:solr_query].present?
|
39
|
+
|
40
|
+
if params[:sort].present?
|
41
|
+
hash[:sort] = params[:sort]
|
42
|
+
hash[:direction] = params[:direction] || "asc"
|
43
|
+
end
|
44
|
+
|
45
|
+
hash
|
46
|
+
end
|
47
|
+
|
48
|
+
# Returns all the active filters for the current search
|
49
|
+
# These filters are used to scope the search results
|
50
|
+
#
|
51
|
+
def filters(filter_type=nil)
|
52
|
+
filters = {}
|
53
|
+
|
54
|
+
symbol = filter_symbol(filter_type)
|
55
|
+
|
56
|
+
memoized_filters = self.instance_variable_get("@#{symbol}_filters")
|
57
|
+
return memoized_filters if memoized_filters
|
58
|
+
|
59
|
+
unlocked = filters_of_type(symbol.to_sym)
|
60
|
+
locked = filters_of_type("#{symbol}l".to_sym)
|
61
|
+
|
62
|
+
filters = Supplejack::Util.deep_merge!(unlocked, locked)
|
63
|
+
|
64
|
+
@all_filters = filters.dup.symbolize_keys.to_hash rescue {}
|
65
|
+
self.instance_variable_set("@#{symbol}_filters", @all_filters)
|
66
|
+
@all_filters
|
67
|
+
end
|
68
|
+
|
69
|
+
def and_filters(filter_type=nil)
|
70
|
+
@and_filters ||= {}
|
71
|
+
@and_filters[filter_symbol(filter_type)] ||= filters(filter_type).reject {|filter, value| filter.to_s.match(/-(.+)/) or is_text_field?(filter)}
|
72
|
+
end
|
73
|
+
|
74
|
+
def is_text_field?(filter)
|
75
|
+
return false if filter.nil?
|
76
|
+
filter.to_s.split(//).last(5).join('').to_s == '_text'
|
77
|
+
end
|
78
|
+
|
79
|
+
def without_filters(filter_type=nil)
|
80
|
+
symbol = filter_symbol(filter_type)
|
81
|
+
@without_filters ||= {}
|
82
|
+
return @without_filters[symbol] if @without_filters[symbol]
|
83
|
+
|
84
|
+
@without_filters[symbol] = {}
|
85
|
+
filters(filter_type).each_pair do |filter, value|
|
86
|
+
if filter.to_s.match(/-(.+)/)
|
87
|
+
@without_filters[symbol][$1.to_sym] = value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
@without_filters[symbol]
|
91
|
+
end
|
92
|
+
|
93
|
+
def all_filters
|
94
|
+
return @all_filters if @all_filters
|
95
|
+
self.filters
|
96
|
+
@all_filters
|
97
|
+
end
|
98
|
+
|
99
|
+
def filter_symbol(filter_type=nil)
|
100
|
+
if filter_type
|
101
|
+
filter_type == :items ? 'i' : 'h'
|
102
|
+
else
|
103
|
+
params[:record_type].to_i == 0 ? 'i' : 'h'
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns the value from the text param and joins any values from
|
108
|
+
# fields which end in _text (ie. creator_text)
|
109
|
+
#
|
110
|
+
# @param [ String ] default_text A string with the user query
|
111
|
+
#
|
112
|
+
def text(default_text=nil)
|
113
|
+
text_values = []
|
114
|
+
text_values << default_text if default_text.present?
|
115
|
+
|
116
|
+
all_filters.each do |filter, value|
|
117
|
+
text_values << value if is_text_field?(filter)
|
118
|
+
end
|
119
|
+
|
120
|
+
return nil if text_values.empty?
|
121
|
+
text_values.join(' ')
|
122
|
+
end
|
123
|
+
|
124
|
+
# Returns the query_fields from the current search filters so that
|
125
|
+
# specific fields can be searched.
|
126
|
+
# The '_text' is removed from the end of the field name
|
127
|
+
#
|
128
|
+
def query_fields
|
129
|
+
query_fields = []
|
130
|
+
|
131
|
+
all_filters.each do |filter, value|
|
132
|
+
if is_text_field?(filter)
|
133
|
+
query_fields << filter.to_s.chomp!('_text').to_sym
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
return nil if query_fields.empty?
|
138
|
+
query_fields
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns one type of filters
|
142
|
+
#
|
143
|
+
# @param [ :i, :il, :h, :hl ] filter_type The symbol of the filter type
|
144
|
+
#
|
145
|
+
def filters_of_type(filter_type)
|
146
|
+
params[filter_type].dup.symbolize_keys.to_hash rescue {}
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns a hash options to be used for generating URL's with all the search state.
|
150
|
+
#
|
151
|
+
# @param [ Hash ] filter_options A hash of options to be able to remove or add filters
|
152
|
+
#
|
153
|
+
# @filter_option option [ Array ] :except A array of filter names to be removed
|
154
|
+
# @filter_options option [ Hash ] :plus A hash with filters and their values to be added
|
155
|
+
#
|
156
|
+
def options(filter_options={})
|
157
|
+
filter_options.reverse_merge!({:except => [], :plus => {}})
|
158
|
+
filter_options[:except] ||= []
|
159
|
+
|
160
|
+
hash = {}
|
161
|
+
{:i => :i_unlocked, :il => :i_locked, :h => :h_unlocked, :hl => :h_locked}.each_pair do |symbol, instance_name|
|
162
|
+
filters = self.send(instance_name).clone || {}
|
163
|
+
|
164
|
+
filters.each_pair do |name, value|
|
165
|
+
filters.delete(name) if value.blank?
|
166
|
+
end
|
167
|
+
|
168
|
+
filter_options[:except].each do |exception|
|
169
|
+
if exception.is_a?(Hash)
|
170
|
+
facet, values_to_delete = exception.first
|
171
|
+
values_to_delete = Util.array(values_to_delete)
|
172
|
+
existing_values = Util.array(filters[facet])
|
173
|
+
new_values = existing_values - values_to_delete
|
174
|
+
|
175
|
+
if new_values.any?
|
176
|
+
new_values = new_values.first if new_values.size == 1
|
177
|
+
filters[facet] = new_values
|
178
|
+
else
|
179
|
+
filters.delete(facet)
|
180
|
+
end
|
181
|
+
else
|
182
|
+
filters.delete(exception)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
if filter_options[:plus].try(:any?) && filter_options[:plus][symbol].try(:any?)
|
187
|
+
filters = Util.deep_merge(filters, filter_options[:plus][symbol])
|
188
|
+
end
|
189
|
+
|
190
|
+
hash[symbol] = filters.symbolize_keys if filters.any?
|
191
|
+
end
|
192
|
+
|
193
|
+
[:text, :direction, :sort].each do |attribute|
|
194
|
+
attribute_value = search.send(attribute)
|
195
|
+
hash.merge!(attribute => attribute_value) if attribute_value.present?
|
196
|
+
end
|
197
|
+
|
198
|
+
unless filter_options[:except].include?(:page)
|
199
|
+
hash.merge!(:page => search.page) if search.page.present? && search.page != 1
|
200
|
+
end
|
201
|
+
|
202
|
+
hash.merge!(:record_type => 1) if search.record_type > 0
|
203
|
+
return hash
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
|
2
|
+
# and is licensed under the GNU General Public License, version 3.
|
3
|
+
# See https://github.com/DigitalNZ/supplejack_client for details.
|
4
|
+
#
|
5
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ
|
6
|
+
# and the Department of Internal Affairs. http://digitalnz.org/supplejack
|
7
|
+
|
8
|
+
module Supplejack
|
9
|
+
|
10
|
+
# The +User+ class represents a User on the Supplejack API
|
11
|
+
#
|
12
|
+
# A User instance can have a relationship to many UserSet objects, this
|
13
|
+
# relationship is managed through the UserSetRelation class which adds
|
14
|
+
# ActiveRecord like behaviour to the relationship.
|
15
|
+
#
|
16
|
+
# A User object can have the following values:
|
17
|
+
# - id
|
18
|
+
# - name
|
19
|
+
# - username
|
20
|
+
# - email
|
21
|
+
# - api_key
|
22
|
+
# - encrypted_password
|
23
|
+
#
|
24
|
+
class User
|
25
|
+
extend Supplejack::Request
|
26
|
+
|
27
|
+
attr_reader :id, :attributes, :api_key, :name, :username, :email, :encrypted_password, :sets_attributes
|
28
|
+
attr_accessor :use_own_api_key, :regenerate_api_key
|
29
|
+
|
30
|
+
def initialize(attributes={})
|
31
|
+
@attributes = attributes.try(:symbolize_keys) || {}
|
32
|
+
@api_key = @attributes[:api_key] || @attributes[:authentication_token]
|
33
|
+
@id = @attributes[:id]
|
34
|
+
@sets_attributes = @attributes[:sets]
|
35
|
+
@use_own_api_key = @attributes[:use_own_api_key] || false
|
36
|
+
@regenerate_api_key = @attributes[:regenerate_api_key] || false
|
37
|
+
|
38
|
+
[:name, :username, :email, :encrypted_password].each do |attr|
|
39
|
+
self.instance_variable_set("@#{attr}", @attributes[attr])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
# Initializes a UserSetRelation class which adds behaviour to build, create
|
44
|
+
# find and order sets related to this particular User instance
|
45
|
+
#
|
46
|
+
# @return [ UserSetRelation ] A UserSetRelation object
|
47
|
+
#
|
48
|
+
# def sets
|
49
|
+
# @sets ||= UserSetRelation.new(self)
|
50
|
+
# end
|
51
|
+
|
52
|
+
# Executes a PUT request to the API with the user attributes
|
53
|
+
#
|
54
|
+
# @return [ true, false ] True if the API returned a success response, false if not.
|
55
|
+
#
|
56
|
+
def save
|
57
|
+
begin
|
58
|
+
updated_user = self.class.put("/users/#{self.api_key}", {}, self.api_attributes)
|
59
|
+
@api_key = updated_user['user']['api_key'] if regenerate_api_key?
|
60
|
+
return true
|
61
|
+
rescue StandardError => e
|
62
|
+
return false
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# Execures a DELETE request to the API to remove the User object.
|
67
|
+
#
|
68
|
+
# @return [ true, false ] True if the API returned a success response, false if not.
|
69
|
+
#
|
70
|
+
def destroy
|
71
|
+
begin
|
72
|
+
id_or_api_key = self.id || self.api_key
|
73
|
+
self.class.delete("/users/#{id_or_api_key}")
|
74
|
+
return true
|
75
|
+
rescue StandardError => e
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns a Hash of attributes which will be sent with the POST request.
|
81
|
+
#
|
82
|
+
# @return [ Hash ] A hash of field names and their values
|
83
|
+
#
|
84
|
+
def api_attributes
|
85
|
+
attrs = {}
|
86
|
+
|
87
|
+
[:name, :username, :email, :encrypted_password].each do |attr|
|
88
|
+
value = self.public_send(attr)
|
89
|
+
attrs[attr] = value if value.present?
|
90
|
+
end
|
91
|
+
|
92
|
+
attrs[:sets] = @sets_attributes if @sets_attributes.present?
|
93
|
+
attrs[:authentication_token] = nil if regenerate_api_key?
|
94
|
+
attrs
|
95
|
+
end
|
96
|
+
|
97
|
+
# Returns true/false depending whether it will use it's own API Key
|
98
|
+
# for managing sets
|
99
|
+
#
|
100
|
+
# @return [ true/false ] False by default, true when intentionally set at user initialization.
|
101
|
+
#
|
102
|
+
def use_own_api_key?
|
103
|
+
!!@use_own_api_key
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns true/false depending whether it will regenerate it's API Key
|
107
|
+
#
|
108
|
+
# @return [ true/false ] False by default, true when intentionally set.
|
109
|
+
#
|
110
|
+
def regenerate_api_key?
|
111
|
+
!!@regenerate_api_key
|
112
|
+
end
|
113
|
+
|
114
|
+
# Executes a GET request to the API to find the user with the provided ID.
|
115
|
+
#
|
116
|
+
# @return [ Supplejack::User ] A Supplejack::User object
|
117
|
+
#
|
118
|
+
def self.find(id)
|
119
|
+
response = get("/users/#{id}")
|
120
|
+
new(response["user"])
|
121
|
+
end
|
122
|
+
|
123
|
+
# Executes a POST request to the API with the user attributes to create a User object.
|
124
|
+
#
|
125
|
+
# @return [ Supplejack::User ] A Supplejack::User object with recently created id and api_key.
|
126
|
+
#
|
127
|
+
def self.create(attributes={})
|
128
|
+
response = post("/users", {}, {user: attributes})
|
129
|
+
new(response["user"])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,349 @@
|
|
1
|
+
# The Supplejack Client code is Crown copyright (C) 2014, New Zealand Government,
|
2
|
+
# and is licensed under the GNU General Public License, version 3.
|
3
|
+
# See https://github.com/DigitalNZ/supplejack_client for details.
|
4
|
+
#
|
5
|
+
# Supplejack was created by DigitalNZ at the National Library of NZ
|
6
|
+
# and the Department of Internal Affairs. http://digitalnz.org/supplejack
|
7
|
+
|
8
|
+
module Supplejack
|
9
|
+
|
10
|
+
# The +UserSet+ class represents a UserSet on the Supplejack API
|
11
|
+
#
|
12
|
+
# A UserSet instance can have many Item objects, the relationship
|
13
|
+
# with the Item objects is managed through the ItemRelation class which adds
|
14
|
+
# ActiveRecord like behaviour to the relationship.
|
15
|
+
#
|
16
|
+
# A Item object can have the following values:
|
17
|
+
# - id
|
18
|
+
# - name
|
19
|
+
# - description
|
20
|
+
# - privacy
|
21
|
+
# - priority
|
22
|
+
# - count
|
23
|
+
# - tags
|
24
|
+
#
|
25
|
+
class UserSet
|
26
|
+
extend Supplejack::Request
|
27
|
+
include ActiveModel::Conversion
|
28
|
+
extend ActiveModel::Naming
|
29
|
+
|
30
|
+
ATTRIBUTES = [:id, :name, :description, :privacy, :url, :priority, :count, :tags, :tag_list, :homepage, :records, :created_at, :updated_at, :approved, :record]
|
31
|
+
attr_accessor *ATTRIBUTES
|
32
|
+
attr_accessor :api_key, :errors, :user
|
33
|
+
|
34
|
+
PRIVACY_STATES = ['public', 'hidden', 'private']
|
35
|
+
|
36
|
+
def initialize(attributes={})
|
37
|
+
@attributes = attributes.try(:symbolize_keys) || {}
|
38
|
+
@user = Supplejack::User.new(@attributes[:user])
|
39
|
+
self.attributes = @attributes
|
40
|
+
end
|
41
|
+
|
42
|
+
def attributes
|
43
|
+
attributes = {}
|
44
|
+
ATTRIBUTES.each do |attribute|
|
45
|
+
value = self.send(attribute)
|
46
|
+
attributes[attribute] = value if value.present?
|
47
|
+
end
|
48
|
+
attributes
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return a Hash of attributes which is used to extract the relevant
|
52
|
+
# UserSet attributes when creating or updating a UserSet
|
53
|
+
#
|
54
|
+
# @return [ Hash ] A hash with field names and their values
|
55
|
+
#
|
56
|
+
def api_attributes
|
57
|
+
api_attributes = {}
|
58
|
+
[:name, :description, :privacy, :priority, :tag_list, :homepage, :approved].each do |attr|
|
59
|
+
api_attributes[attr] = self.send(attr)
|
60
|
+
end
|
61
|
+
api_attributes[:records] = self.api_records
|
62
|
+
api_attributes
|
63
|
+
end
|
64
|
+
|
65
|
+
# Return a array of hashes with the format: {record_id: 123, position: 1}
|
66
|
+
# Each hash represents a Supplejack::Item within the UserSet
|
67
|
+
#
|
68
|
+
# This array is used to send the UserSet items information to the API.
|
69
|
+
#
|
70
|
+
# @return [ Array ] An array of Hashes.
|
71
|
+
#
|
72
|
+
def api_records
|
73
|
+
records = self.records.is_a?(Array) ? self.records : []
|
74
|
+
records.map do |record_hash|
|
75
|
+
record_hash = record_hash.try(:symbolize_keys) || {}
|
76
|
+
if record_hash[:record_id]
|
77
|
+
{record_id: record_hash[:record_id], position: record_hash[:position] }
|
78
|
+
else
|
79
|
+
nil
|
80
|
+
end
|
81
|
+
end.compact
|
82
|
+
end
|
83
|
+
|
84
|
+
# Initializes a ItemRelation class which adds behaviour to build, create and
|
85
|
+
# find items related to this particular UserSet instance
|
86
|
+
#
|
87
|
+
# @return [ ItemRelation ] A ItemRelation object
|
88
|
+
#
|
89
|
+
def items
|
90
|
+
@items ||= ItemRelation.new(self)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Returns the UserSet priority which defaults to 1
|
94
|
+
#
|
95
|
+
def priority
|
96
|
+
@priority || 1
|
97
|
+
end
|
98
|
+
|
99
|
+
# Returns the api_key from the UserSet or from the User which this set belongs to.
|
100
|
+
#
|
101
|
+
def api_key
|
102
|
+
@api_key || @user.try(:api_key)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Returns a comma separated list of tags for this UserSet
|
106
|
+
#
|
107
|
+
def tag_list
|
108
|
+
return @tag_list if @tag_list
|
109
|
+
self.tags.join(', ') if self.tags
|
110
|
+
end
|
111
|
+
|
112
|
+
def favourite?
|
113
|
+
self.name == "Favourites"
|
114
|
+
end
|
115
|
+
|
116
|
+
def private?
|
117
|
+
self.privacy == "private"
|
118
|
+
end
|
119
|
+
|
120
|
+
def public?
|
121
|
+
self.privacy == "public"
|
122
|
+
end
|
123
|
+
|
124
|
+
def hidden?
|
125
|
+
self.privacy == "hidden"
|
126
|
+
end
|
127
|
+
|
128
|
+
# Convinience method to find out if a particular record_id is part of the UserSet
|
129
|
+
#
|
130
|
+
# @param [ Integer ] A record_id
|
131
|
+
#
|
132
|
+
# @return [ true, false ] True if the provided record_id is part of the UserSet, false otherwise.
|
133
|
+
#
|
134
|
+
def has_record?(record_id)
|
135
|
+
!!self.items.detect {|i| i.record_id == record_id.to_i }
|
136
|
+
end
|
137
|
+
|
138
|
+
# Returns the record id of the associated record in a safe manner
|
139
|
+
#
|
140
|
+
# @return [Intger, nil ] the record id if it exists, false otherwise
|
141
|
+
def set_record_id
|
142
|
+
self.record['record_id'] if self.record
|
143
|
+
end
|
144
|
+
|
145
|
+
# Executes a POST request when the UserSet hasn't been persisted to the API, otherwise it executes
|
146
|
+
# a PUT request.
|
147
|
+
#
|
148
|
+
# When the API returns a error response, the errors are available through the UserSet#errors
|
149
|
+
# virtual attribute.
|
150
|
+
#
|
151
|
+
# @return [ true, false ] True if the API response was successful, false if not.
|
152
|
+
#
|
153
|
+
def save
|
154
|
+
begin
|
155
|
+
if self.new_record?
|
156
|
+
response = self.class.post("/sets", {api_key: self.api_key}, {set: self.api_attributes})
|
157
|
+
self.id = response["set"]["id"]
|
158
|
+
else
|
159
|
+
self.class.put("/sets/#{self.id}", {api_key: self.api_key}, {set: self.api_attributes})
|
160
|
+
end
|
161
|
+
Rails.cache.delete("/users/#{self.api_key}/sets") if Supplejack.enable_caching
|
162
|
+
return true
|
163
|
+
rescue StandardError => e
|
164
|
+
self.errors = e.inspect
|
165
|
+
return false
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Updates the UserSet attributes and persists it to the API
|
170
|
+
#
|
171
|
+
# @return [ true, false ] True if the API response was successful, false if not.
|
172
|
+
#
|
173
|
+
def update_attributes(attributes={})
|
174
|
+
self.attributes = attributes
|
175
|
+
self.save
|
176
|
+
end
|
177
|
+
|
178
|
+
# Assigns the provided attributes to the UserSet object
|
179
|
+
#
|
180
|
+
def attributes=(attributes)
|
181
|
+
attributes = attributes.try(:symbolize_keys) || {}
|
182
|
+
attributes.each do |attr, value|
|
183
|
+
self.send("#{attr}=", value) if ATTRIBUTES.include?(attr)
|
184
|
+
end
|
185
|
+
self.records = ordered_records_from_array(attributes[:ordered_records]) if attributes[:ordered_records]
|
186
|
+
end
|
187
|
+
|
188
|
+
# Define setter methods for both created_at and updated_at so that
|
189
|
+
# they always return a Time object.
|
190
|
+
#
|
191
|
+
[:created_at, :updated_at].each do |attribute|
|
192
|
+
define_method("#{attribute}=") do |time|
|
193
|
+
self.instance_variable_set("@#{attribute}", Util.time(time))
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Takes an ordered Array of record_ids and converts it into a Array
|
198
|
+
# of Hashes which the API expects, inferring the position value from
|
199
|
+
# the position of the record_id in the Array.
|
200
|
+
#
|
201
|
+
# @param [ Array ] A array of record_ids
|
202
|
+
#
|
203
|
+
# @return [ Array ] A array of hashes in the format {record_id: 1, position: 1}
|
204
|
+
#
|
205
|
+
# @example
|
206
|
+
# user_set.ordered_records_from_array([89,66]) => [{record_id: 89, position: 1}, {record_id: 66, position: 2}]
|
207
|
+
#
|
208
|
+
def ordered_records_from_array(record_ids)
|
209
|
+
records = []
|
210
|
+
record_ids.each_with_index do |id, index|
|
211
|
+
records << {record_id: id, position: index+1}
|
212
|
+
end
|
213
|
+
records
|
214
|
+
end
|
215
|
+
|
216
|
+
# Returns if the UserSet is persisted to the API or not.
|
217
|
+
#
|
218
|
+
# @return [ true, false ] True if the UserSet is persisted to the API, false if not.
|
219
|
+
#
|
220
|
+
def new_record?
|
221
|
+
self.id.blank?
|
222
|
+
end
|
223
|
+
|
224
|
+
# Executes a DELETE request to the API with the UserSet ID and the user's api_key
|
225
|
+
#
|
226
|
+
# @return [ true, false ] True if the API response was successful, false if not.
|
227
|
+
#
|
228
|
+
def destroy
|
229
|
+
if self.new_record?
|
230
|
+
return false
|
231
|
+
else
|
232
|
+
begin
|
233
|
+
self.class.delete("/sets/#{self.id}", {api_key: self.api_key})
|
234
|
+
Rails.cache.delete("/users/#{self.api_key}/sets") if Supplejack.enable_caching
|
235
|
+
return true
|
236
|
+
rescue StandardError => e
|
237
|
+
self.errors = e.inspect
|
238
|
+
return false
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def persisted?
|
244
|
+
!new_record?
|
245
|
+
end
|
246
|
+
|
247
|
+
# Fetches the UserSet information from the API again, in case it had changed.
|
248
|
+
# This can be useful if they items for a UserSet changed and you want the relation
|
249
|
+
# to have the most up to date items.
|
250
|
+
#
|
251
|
+
def reload
|
252
|
+
begin
|
253
|
+
self.instance_variable_set("@items", nil)
|
254
|
+
self.attributes = self.class.get("/sets/#{self.id}")["set"]
|
255
|
+
rescue RestClient::ResourceNotFound => e
|
256
|
+
raise Supplejack::SetNotFound, "UserSet with ID #{id} was not found"
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
# A UserSet is viewable by anyone if it's public or hidden
|
261
|
+
# When the UserSet is private it's only viewable by the owner.
|
262
|
+
#
|
263
|
+
# @param [ Supplejack::User ] A Supplejack::User object
|
264
|
+
#
|
265
|
+
# @return [ true, false ] True if the user can view the current UserSet, false if not.
|
266
|
+
#
|
267
|
+
def viewable_by?(user)
|
268
|
+
return true if self.public? || self.hidden?
|
269
|
+
self.owned_by?(user)
|
270
|
+
end
|
271
|
+
|
272
|
+
# Compares the api_key of the user and the api_key assigned to the UserSet
|
273
|
+
# to find out if the user passed is the owner of the set.
|
274
|
+
#
|
275
|
+
# @param [ Supplejack::User ] A Supplejack::User object
|
276
|
+
#
|
277
|
+
# @return [ true, false ] True if the user owns the current UserSet, false if not.
|
278
|
+
#
|
279
|
+
def owned_by?(user)
|
280
|
+
return false if user.try(:api_key).blank? || self.api_key.blank?
|
281
|
+
user.try(:api_key) == self.api_key
|
282
|
+
end
|
283
|
+
|
284
|
+
# Executes a GET request with the provided UserSet ID and initializes
|
285
|
+
# a UserSet object with the response from the API.
|
286
|
+
#
|
287
|
+
# @return [ UserSet ] A UserSet object
|
288
|
+
#
|
289
|
+
def self.find(id, api_key=nil)
|
290
|
+
begin
|
291
|
+
response = get("/sets/#{id}")
|
292
|
+
attributes = response["set"] || {}
|
293
|
+
user_set = new(attributes)
|
294
|
+
user_set.api_key = api_key if api_key.present?
|
295
|
+
user_set
|
296
|
+
rescue RestClient::ResourceNotFound => e
|
297
|
+
raise Supplejack::SetNotFound, "UserSet with ID #{id} was not found"
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
# Executes a GET request to the API /sets/public endpoint to retrieve
|
302
|
+
# all public UserSet objects.
|
303
|
+
#
|
304
|
+
# @param [ Hash ] options Supported options: :page, :per_page
|
305
|
+
#
|
306
|
+
# @option options [ Integer ] :page The page number used to paginate through the UserSet objects
|
307
|
+
# @option options [ Integer ] :per_page The per_page number to select the number of UserSet objects per page.
|
308
|
+
#
|
309
|
+
# @return [ Array ] A array of Supplejack::UserSet objects
|
310
|
+
#
|
311
|
+
def self.public_sets(options={})
|
312
|
+
options.reverse_merge!(page: 1, per_page: 100)
|
313
|
+
response = get("/sets/public", options)
|
314
|
+
sets_array = response["sets"] || []
|
315
|
+
user_sets = sets_array.map {|attrs| new(attrs) }
|
316
|
+
Supplejack::PaginatedCollection.new(user_sets, options[:page].to_i, options[:per_page].to_i, response["total"].to_i)
|
317
|
+
end
|
318
|
+
|
319
|
+
# Execute a GET request to the API /sets/home endpoint to retrieve
|
320
|
+
# all UserSet objects which have the :homepage flag set to true
|
321
|
+
#
|
322
|
+
# @return [ Array ] A array of Supplejack::UserSet objects
|
323
|
+
#
|
324
|
+
def self.homepage_sets
|
325
|
+
path = "/sets/home"
|
326
|
+
if Supplejack.enable_caching
|
327
|
+
response = Rails.cache.fetch(path, expires_in: 1.day) do
|
328
|
+
get(path)
|
329
|
+
end
|
330
|
+
else
|
331
|
+
response = get(path)
|
332
|
+
end
|
333
|
+
sets_array = response["sets"] || []
|
334
|
+
user_sets = sets_array.map {|attrs| new(attrs) }
|
335
|
+
end
|
336
|
+
|
337
|
+
# This method is normally provided by ActiveModel::Naming module, but here we have to override it
|
338
|
+
# so that in the Supplejack Website application it behaves as if the Supplejack::UserSet class was not under the
|
339
|
+
# Supplejack namespace.
|
340
|
+
#
|
341
|
+
# This is useful when using a Supplejack::UserSet object in the Rails provided routes helpers. Example:
|
342
|
+
#
|
343
|
+
# user_set_path(@user_set)
|
344
|
+
#
|
345
|
+
def self.model_name
|
346
|
+
ActiveModel::Name.new(self, nil, "UserSet")
|
347
|
+
end
|
348
|
+
end
|
349
|
+
end
|