StarRezApi 0.2.3

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.
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,23 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+
5
+ desc 'Default: run unit tests.'
6
+ task :default => :test
7
+
8
+ desc 'Test the starrez_api plugin.'
9
+ Rake::TestTask.new(:test) do |t|
10
+ t.libs << 'lib'
11
+ t.libs << 'test'
12
+ t.pattern = 'test/**/*_test.rb'
13
+ t.verbose = true
14
+ end
15
+
16
+ desc 'Generate documentation for the starrez_api plugin.'
17
+ Rake::RDocTask.new(:rdoc) do |rdoc|
18
+ rdoc.rdoc_dir = 'rdoc'
19
+ rdoc.title = 'StarrezApi'
20
+ rdoc.options << '--line-numbers' << '--inline-source'
21
+ rdoc.rdoc_files.include('README')
22
+ rdoc.rdoc_files.include('lib/**/*.rb')
23
+ end
@@ -0,0 +1,8 @@
1
+ development:
2
+ base_uri: https://localhost/StarRezPortalREST/services/
3
+
4
+ production:
5
+ base_uri: https://localhost/StarRezPortalREST/services/
6
+
7
+ test:
8
+ base_uri: https://localhost/StarRezPortalREST/services/
@@ -0,0 +1,22 @@
1
+ # StarRez REST Web Services and Report API
2
+
3
+ # Load our configuration
4
+ if File.exists?(File.join(Rails.root,"config","starrez.yml"))
5
+ config_path = File.join(Rails.root,"config","starrez.yml")
6
+ else
7
+ config_path = File.dirname(__FILE__) + "/starrez.yml"
8
+ end
9
+ STARREZ_CONFIG = YAML.load_file(config_path)[Rails.env]
10
+
11
+ # Check for required gems
12
+ begin
13
+ require 'httparty'
14
+ HTTParty
15
+ rescue Exception => e
16
+ puts "HTTParty is a required GEM for this plugin. Solve by typing: gem install httparty"
17
+ end
18
+
19
+ # Load our Plugin files
20
+ require 'starrez_api/object'
21
+ require 'starrez_api/star_rez_api'
22
+ require 'starrez_api/star_rez_report'
@@ -0,0 +1,19 @@
1
+ # Much props to _why and his (poignant) guide
2
+ # This code can originally be found at
3
+ # http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html
4
+
5
+ class Object
6
+ # The hidden singleton lurks behind everyone
7
+ def metaclass; class << self; self; end; end
8
+ def meta_eval &blk; metaclass.instance_eval &blk; end
9
+
10
+ # Adds methods to a metaclass
11
+ def meta_def name, &blk
12
+ meta_eval { define_method name, &blk }
13
+ end
14
+
15
+ # Defines an instance method within a class
16
+ def class_def name, &blk
17
+ class_eval { define_method name, &blk }
18
+ end
19
+ end
@@ -0,0 +1,312 @@
1
+ require 'httparty'
2
+ require 'xmlsimple'
3
+
4
+ module StarRezApi
5
+ include HTTParty
6
+ base_uri STARREZ_CONFIG['base_uri']
7
+
8
+ def self.included receiver
9
+ receiver.extend ClassMethods
10
+ end
11
+
12
+ module ClassMethods
13
+ def first
14
+ results = find(:first)
15
+ end
16
+
17
+ def url
18
+ "#{StarRezApi::base_uri}/select/#{self.name.gsub(/.*\:\:/,'').downcase}.xml/?_top=1"
19
+ end
20
+
21
+ def what_am_i?
22
+ "#{self.class.name}"
23
+ end
24
+
25
+ def class_name
26
+ self.name.gsub(/.*\:\:/,'')
27
+ end
28
+
29
+ def populate_variables(hash, related_tables=[])
30
+ self.instance_variable_set("@original_hash",hash)
31
+ hash.each do |k,v|
32
+ if related_tables.include? k.to_s
33
+ children = Array.new
34
+ v = [v] unless v.is_a? Array # This handles the instance of a single-child
35
+ v.each do |child|
36
+ new_child = self.clone
37
+ new_child.populate_variables(child)
38
+ children << new_child
39
+ end
40
+ new_k = k.to_s.underscore.pluralize
41
+ self.instance_variable_set("@#{new_k}", children)
42
+ meta_def new_k do
43
+ self.instance_variable_get("@#{new_k}")
44
+ end
45
+ meta_def "#{new_k}=" do |v|
46
+ self.instance_variable_set("@#{new_k}",v)
47
+ end
48
+ elsif k.is_a?(Hash)
49
+ # Ignore sub-objects
50
+ else
51
+ unless k.blank?
52
+ k = k.to_s.underscore
53
+ self.instance_variable_set("@#{k}",v)
54
+ meta_def k do
55
+ self.instance_variable_get("@#{k}")
56
+ end
57
+ meta_def "#{k}=" do |v|
58
+ self.instance_variable_set("@#{k}",v)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+
65
+ def id
66
+ self.send "#{self.class_name.underscore}_id"
67
+ end
68
+
69
+ def changed
70
+ changed_attributes = Hash.new
71
+ self.instance_variable_get("@original_hash").each do |k,v|
72
+ k = k.to_s.underscore
73
+ current_value = self.send(k.to_sym)
74
+ unless current_value.eql? v
75
+ changed_attributes[k.to_sym] = [v, current_value]
76
+ end
77
+ end
78
+ return changed_attributes
79
+ end
80
+
81
+ def changed?
82
+ self.changed.size > 0
83
+ end
84
+
85
+ def save
86
+ if self.changed?
87
+ response = StarRezApi::post("#{StarRezApi::base_uri}/update/#{self.class_name}/#{self.id}", :body => self.build_query(self.changed))
88
+ if response.code.eql? 200
89
+ original_hash = self.instance_variable_get("@original_hash")
90
+ self.build_query(self.changed).keys.each do |attribute|
91
+ original_hash[attribute.to_s] = self.send(attribute.to_s.underscore.to_sym)
92
+ end
93
+ self.instance_variable_set("@original_hash",original_hash)
94
+ return true
95
+ else
96
+ return response
97
+ end
98
+ else
99
+ warn "[WARN] Nothing to save"
100
+ return false
101
+ end
102
+ end
103
+
104
+ def create(attribute_hash = {}, options ={})
105
+ formatted_hash = Hash.new
106
+ attribute_hash.each_pair { |column, value| formatted_hash[column.to_s.camelize.to_sym] = value }
107
+ results = StarRezApi::post("#{StarRezApi::base_uri}/create/#{self.class_name}", :body => formatted_hash)
108
+ if results.code.eql? 200
109
+ if options[:return].eql? :boolean
110
+ return true
111
+ else
112
+ response = XmlSimple.xml_in(results.body)
113
+ new_id = response["entry"][0]["content"]
114
+ return self.find new_id
115
+ end
116
+ elsif results.code.eql? 400
117
+ return false
118
+ else
119
+ return false
120
+ end
121
+ end
122
+
123
+
124
+ def all(page_index = 1, page_size = 50)
125
+ return find(:all, {:size => page_size, :page => page_index})
126
+ end
127
+
128
+
129
+
130
+ # Find objects via the API interface
131
+ # Returns an object defined on demand by the API result
132
+ #
133
+ # An Object ID or one of the following symbols (:all, :first) must be the first argument
134
+ # +id+:: The ID of the Object your are searching
135
+ # +:all+:: Returns an array of objects
136
+ # +:first+:: Returns the first matched object
137
+ #
138
+ #
139
+ # The following options are not required but can be used to refine the search
140
+ # +:conditions+:: Field-Value Pairs
141
+ # +:page+:: The index page for pagination
142
+ # +:size+:: The number of results returned per page
143
+ # +:fields+:: An array of field names to return
144
+ # +:include+:: Include related tables (this only works if you go from parent->child)
145
+ # +:order+:: An array of field names to order the response by.
146
+ # +:limit+:: The number of results to return
147
+ #
148
+ # The +conditions+ option should be a hash with key-value pairs related to the search
149
+ # requirements. Due to the nature of the StarRez API, there is an additional complexity
150
+ # of seach operands. For this reason the conditions can be in either of the following
151
+ # two formats:
152
+ #
153
+ # { :column_name => value }
154
+ #
155
+ # { :column_name => { :operand => value } }
156
+ #
157
+ # Available Operands are:
158
+ #
159
+ # +ne+:: Not Equals
160
+ # +gt+:: Greater Than
161
+ # +lt+:: Less Than
162
+ # +gte+:: Greater Than or Equal To
163
+ # +lte+:: Less Than or Equal To
164
+ # +c+:: Contains
165
+ # +nc+:: Not Contains
166
+ # +sw+:: Starts With
167
+ # +nsw+:: Not Starts With
168
+ # +ew+:: Ends With
169
+ # +new+:: Not Ends With
170
+ # +in+:: Value is in (comma separated integer list)
171
+ # +notin+:: Value is not in (comma separated integer list)
172
+ #
173
+ # The +fields+ option should be an Array of either symbols or strings which refer to a
174
+ # column in the field. There is no error checking prior to the submission, so an invalid
175
+ # field name will result in an error.
176
+ #
177
+ # The +include+ option should be an Array of either symbols or strings which refer to a
178
+ # related tables in the database. There is no error checking and an invalid relationship
179
+ # will result in a failure. This will create an instance variable of an Array of the
180
+ # returned objects which will be accessible by a method with the table name pluralized.
181
+ #
182
+ # The +order+ option should be an array of fields which the response is ordered by. If
183
+ # You wish to search by descending order, use a key value of :desc. For example:
184
+ # :order => [:name_last, :name_first => :desc]
185
+ #
186
+ #
187
+ # Usage:
188
+ #
189
+ # # Search for a single Entry with the ID of 1234
190
+ # Entry.find(1234)
191
+ #
192
+ # # Search for all entries with the last name 'Smith'
193
+ # Entry.find(:all, :conditions => { :name_last => "Smith"})
194
+ #
195
+ # # Search for all entries with the last name that starts with 'Sm' and only return first and last names
196
+ # Entry.find(:all, :conditions => { :name_last => { :sw => "Sm" } }, :fields => [:name_last, :name_first])
197
+ #
198
+ # # Search for all rooms on a specific floor ('654')
199
+ # RoomLocationFloorSuite(654, :include => [:room])
200
+
201
+
202
+ def find(entry, options = {})
203
+ options[:size] ||= 50
204
+ options[:page] = options[:page].blank? || options[:page] == 1 ? 0 : options[:page] * options[:size]
205
+ query_array = Array.new
206
+ unless options[:conditions].blank?
207
+ query_array << get_condition_string(options[:conditions])
208
+ end
209
+ if entry.is_a?(Symbol)
210
+ get_url = "#{StarRezApi::base_uri}/select/#{self.class_name}.xml/"
211
+ else
212
+ get_url = "#{StarRezApi::base_uri}/select/#{self.class_name}.xml/#{entry}"
213
+ end
214
+ if entry.eql? :first
215
+ query_array << "_top=1"
216
+ elsif entry.eql? :all
217
+ query_array << "_pageIndex=#{options[:page]}"
218
+ query_array << "_pageSize=#{options[:size]}"
219
+ end
220
+ unless options[:fields].blank?
221
+ fields = Array.new
222
+ options[:fields].each { |f| fields << f.to_s.camelize }
223
+ query_array << "_fields=#{fields.join(',')}"
224
+ end
225
+ tables = Array.new
226
+ unless options[:include].blank?
227
+ options[:include].each { |t| tables << t.to_s.camelize }
228
+ query_array << "_relatedtables=#{tables.join(',')}"
229
+ end
230
+ unless options[:order].blank?
231
+ order = Array.new
232
+ options[:order].each { |o| order << (options[:order][o].eql? :desc) ? "#{o.to_s.camelize}.desc" : "#{o.to_s.camelize}"}
233
+ query_array << "_orderby=#{order.join(',')}"
234
+ end
235
+ unless options[:limit].blank?
236
+ query_array << "_top=#{options[:limit]}"
237
+ end
238
+ get_url += "?#{query_array.join('&')}"
239
+ results = StarRezApi::get(get_url)
240
+ if results.response.is_a?(Net::HTTPNotFound)
241
+ return nil
242
+ elsif results.code.eql? 403
243
+ raise SecurityError, "Access Denied to API"
244
+ elsif options[:return].eql? :response
245
+ return results
246
+ elsif results.code.eql? 200
247
+ ret = results["Results"][self.class_name]
248
+ else
249
+ return results
250
+ end
251
+ if ret.is_a?(Hash)
252
+ self.populate_variables(ret,tables)
253
+ if entry.eql? :all
254
+ return [self]
255
+ else
256
+ return self
257
+ end
258
+ else
259
+ results = Array.new
260
+ ret.each do |entry_hash|
261
+ new_entry = self.clone
262
+ new_entry.populate_variables(entry_hash,tables)
263
+ results << new_entry
264
+ end
265
+ return results
266
+ end
267
+ end
268
+
269
+
270
+ def build_query(hash)
271
+ query = Hash.new
272
+ hash.keys.each do |attribute|
273
+ query[attribute.to_s.camelize.to_sym] = self.send(attribute)
274
+ end
275
+ return query
276
+ end
277
+
278
+ private
279
+
280
+ #Just a quick method used in get_condition_string that would have been repeated
281
+ #Just takes the array and converts it into a formatted string for StarRezAPI
282
+ def parse_value(values)
283
+ if values.is_a?(Array)
284
+ return URI::encode(values.join(','))
285
+ else
286
+ return URI::encode(values.to_s)
287
+ end
288
+ end
289
+
290
+ # Coditions Clean-up by Dan
291
+ # Example:
292
+ # find(:all, :conditions => { :column_name => value, :column_name => { :operator => value } })
293
+
294
+ def get_condition_string(conditions)
295
+ queries = Array.new
296
+ if conditions.is_a?(Hash)
297
+ conditions.each_pair do |column, value|
298
+ query = column.to_s.camelize
299
+ if value.is_a?(Hash)
300
+ query += "[_operator%3D#{value.keys.first.to_s}]=#{parse_value(value[value.keys.first])}"
301
+ else
302
+ query += "=#{parse_value(value)}"
303
+ end
304
+ queries << query
305
+ end
306
+ return queries.join('&')
307
+ else
308
+ raise ArgumentError, "Condition needs to be a hash of values, Please review the source code"
309
+ end
310
+ end
311
+ end
312
+ end
@@ -0,0 +1,88 @@
1
+ require 'httparty'
2
+ class StarRezReport
3
+ include HTTParty
4
+ base_uri STARREZ_CONFIG['base_uri']
5
+ attr_accessor :name, :results
6
+
7
+ def self.find_by_id(entry, options = {})
8
+ if entry.blank?
9
+ raise IOError, "Must include a report ID to search"
10
+ end
11
+ conditions = options[:conditions].blank? ? '' : "?#{self.get_condition_string(options[:conditions])}"
12
+ url = "#{base_uri}/getreportbyid/#{entry}.xml/#{conditions}"
13
+ response = get(url)
14
+ if options[:return].eql? :response
15
+ return response
16
+ else
17
+ return self.parse_response(response)
18
+ end
19
+ end
20
+
21
+ def self.find_by_name(name, options = {})
22
+ if name.blank?
23
+ raise IOError, "Must include a report name"
24
+ end
25
+ conditions = options[:conditions].blank? ? '' : "?#{self.get_condition_string(options[:conditions])}"
26
+ url = "#{base_uri}/getreportbyname/#{URI::escape(name.to_s)}.xml/#{conditions}"
27
+ response = get(url)
28
+ if options[:return].eql? :response
29
+ return response
30
+ else
31
+ return self.parse_response(response)
32
+ end
33
+ end
34
+
35
+ private
36
+ # Parse the response from the API
37
+ def self.parse_response(response)
38
+ if response.code.eql? 200
39
+ report = StarRezReport.new
40
+ report.name = response.keys.first
41
+ if response[report.name].blank?
42
+ report.results = []
43
+ else
44
+ if response[report.name]["Record"].is_a? Hash
45
+ report.results = [response[report.name]["Record"]]
46
+ else
47
+ report.results = response[report.name]["Record"]
48
+ end
49
+ end
50
+ return report
51
+ elsif response.code.eql? 403
52
+ raise SecurityError, "Access Denied to API"
53
+ else
54
+ return false
55
+ end
56
+ end
57
+
58
+ # Coditions Clean-up by Dan
59
+ # Example:
60
+ # find(:all, :conditions => { :column_name => value, :column_name => { :operator => value } })
61
+ def self.get_condition_string(conditions)
62
+ queries = Array.new
63
+ if conditions.is_a?(Hash)
64
+ conditions.each_pair do |column, value|
65
+ query = column.to_s.camelize
66
+ if value.is_a?(Hash)
67
+ query += "[_operator%3D#{value.keys.first.to_s}]=#{self.parse_value(value[value.keys.first])}"
68
+ else
69
+ query += "=#{self.parse_value(value)}"
70
+ end
71
+ queries << query
72
+ end
73
+ return queries.join('&')
74
+ else
75
+ raise ArgumentError, "Condition needs to be a hash of values, Please review the source code"
76
+ end
77
+ end
78
+
79
+ #Just a quick method used in get_condition_string that would have been repeated
80
+ #Just takes the array and converts it into a formatted string for StarRezAPI
81
+ def self.parse_value(values)
82
+ if values.is_a?(Array)
83
+ return URI::encode(values.join(','))
84
+ else
85
+ return URI::encode(values.to_s)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :starrez_api do
3
+ # # Task goes here
4
+ # end
@@ -0,0 +1,2 @@
1
+ # Include hook code here
2
+ require 'starrez_api'
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: StarRezApi
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.2.3
6
+ platform: ruby
7
+ authors:
8
+ - Daniel Reedy
9
+ - Steven Stephen
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+
14
+ date: 2011-06-15 00:00:00 Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: httparty
18
+ prerelease: false
19
+ requirement: &id001 !ruby/object:Gem::Requirement
20
+ none: false
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 0.7.4
25
+ type: :runtime
26
+ version_requirements: *id001
27
+ - !ruby/object:Gem::Dependency
28
+ name: xml-simple
29
+ prerelease: false
30
+ requirement: &id002 !ruby/object:Gem::Requirement
31
+ none: false
32
+ requirements:
33
+ - - ">="
34
+ - !ruby/object:Gem::Version
35
+ version: 1.0.12
36
+ type: :runtime
37
+ version_requirements: *id002
38
+ description: This gem that allows the user access to the StarRez REST Web Services and Reporting API
39
+ email: dreedy@housing.siu.edu
40
+ executables: []
41
+
42
+ extensions: []
43
+
44
+ extra_rdoc_files: []
45
+
46
+ files:
47
+ - lib/starrez.yml
48
+ - lib/starrez_api/object.rb
49
+ - lib/starrez_api/star_rez_api.rb
50
+ - lib/starrez_api/star_rez_report.rb
51
+ - lib/starrez_api.rb
52
+ - lib/tasks/starrez_api.rake
53
+ - rails/init.rb
54
+ - MIT-LICENSE
55
+ - Rakefile
56
+ homepage: http://www.housing.siu.edu
57
+ licenses: []
58
+
59
+ post_install_message:
60
+ rdoc_options: []
61
+
62
+ require_paths:
63
+ - lib
64
+ required_ruby_version: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ version: "0"
70
+ required_rubygems_version: !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: "0"
76
+ requirements: []
77
+
78
+ rubyforge_project:
79
+ rubygems_version: 1.8.5
80
+ signing_key:
81
+ specification_version: 3
82
+ summary: A module mixin that allows a class to access StarRez
83
+ test_files: []
84
+