supplejack_client 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +16 -0
  5. data/Guardfile +24 -0
  6. data/LICENSE.txt +674 -0
  7. data/README.md +153 -0
  8. data/Rakefile +9 -0
  9. data/lib/generators/locales/en.yml +11 -0
  10. data/lib/generators/supplejack/install_generator.rb +28 -0
  11. data/lib/generators/templates/README +19 -0
  12. data/lib/generators/templates/supplejack_client.rb +120 -0
  13. data/lib/supplejack/config.rb +116 -0
  14. data/lib/supplejack/controllers/helpers.rb +172 -0
  15. data/lib/supplejack/engine.rb +20 -0
  16. data/lib/supplejack/exceptions.rb +17 -0
  17. data/lib/supplejack/facet.rb +33 -0
  18. data/lib/supplejack/item.rb +94 -0
  19. data/lib/supplejack/item_relation.rb +73 -0
  20. data/lib/supplejack/log_subscriber.rb +58 -0
  21. data/lib/supplejack/paginated_collection.rb +61 -0
  22. data/lib/supplejack/record.rb +147 -0
  23. data/lib/supplejack/request.rb +95 -0
  24. data/lib/supplejack/search.rb +346 -0
  25. data/lib/supplejack/url_formats/item_hash.rb +208 -0
  26. data/lib/supplejack/user.rb +132 -0
  27. data/lib/supplejack/user_set.rb +349 -0
  28. data/lib/supplejack/user_set_relation.rb +143 -0
  29. data/lib/supplejack/util.rb +120 -0
  30. data/lib/supplejack/version.rb +10 -0
  31. data/lib/supplejack_client.rb +29 -0
  32. data/spec/spec_helper.rb +23 -0
  33. data/spec/supplejack/controllers/helpers_spec.rb +277 -0
  34. data/spec/supplejack/facet_spec.rb +44 -0
  35. data/spec/supplejack/item_relation_spec.rb +111 -0
  36. data/spec/supplejack/item_spec.rb +115 -0
  37. data/spec/supplejack/log_subscriber_spec.rb +40 -0
  38. data/spec/supplejack/paginated_collection_spec.rb +43 -0
  39. data/spec/supplejack/record_spec.rb +255 -0
  40. data/spec/supplejack/request_spec.rb +195 -0
  41. data/spec/supplejack/search_spec.rb +727 -0
  42. data/spec/supplejack/url_formats/item_hash_spec.rb +341 -0
  43. data/spec/supplejack/user_set_relation_spec.rb +149 -0
  44. data/spec/supplejack/user_set_spec.rb +465 -0
  45. data/spec/supplejack/user_spec.rb +159 -0
  46. data/supplejack_client.gemspec +30 -0
  47. 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