openapply 0.2.10 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,219 +0,0 @@
1
- # SINGLE STUDENT API GET CALLS
2
- ##############################
3
-
4
- module Get
5
-
6
- # STUDENT FULL RECORD
7
- #####################
8
-
9
- # Summary record for ONE student - this API return has the parent info 2x!
10
- #
11
- # ==== Attributes
12
- # # @student_id - openapply student_id
13
- # * @options - see httparty options
14
- #
15
- # ==== Example code
16
- # @demo = Openapply.new
17
- # @demo.student_by_id(96)
18
- def student_by_id(student_id, options ={})
19
- url = "#{api_path}#{student_id}?auth_token=#{api_key}"
20
- return oa_answer( url, options )
21
- end
22
- alias_method :student, :student_by_id
23
-
24
-
25
- # STUDENT PAYMENT INFO
26
- ######################
27
-
28
- # Payment details for ONE student
29
- #
30
- # ==== Attributes
31
- # * +student_id+ - openapply student_id
32
- # * +options+ - see httparty options
33
- #
34
- # ==== Example code
35
- # @demo = Openapply.new
36
- # @demo.payments_by_id(96)
37
- def payments_by_id(student_id, options={})
38
- url = "#{api_path}#{student_id}/payments?auth_token=#{api_key}"
39
- return oa_answer( url, options )
40
- end
41
- alias_method :payments, :payments_by_id
42
-
43
-
44
- # STUDENT FULL RECORD AND PAYMENTS COMBINED
45
- ###########################################
46
-
47
- # Combines the student_by_id & payments_by_id into one call with all the data
48
- #
49
- # ==== Attributes
50
- # * +student_id+ - openapply student_id
51
- # * +flatten_keys+ - an array of keys to bring to the top level
52
- # (with this key prepened) -- default (blank does nothing)
53
- # * +reject_keys+ - an array of keys to remove from the data -- default (blank does nothing)
54
- # * +get_payments+ - default is true (but needs double lookup) - faster when false!
55
- #
56
- # === Usage
57
- # students_details_by_id(95)
58
- # students_details_by_id(95, [], [], false)
59
- # students_details_by_id(95, [:custom_fields], [:parent_guardian])
60
- # students_details_by_id(95, [:custom_fields], [:parent_guardian], false)
61
- #
62
- # === Returned Data
63
- # returns the data structured as:
64
- # { student:
65
- # { id: xxx,
66
- # record: {xxx} # complete student record
67
- # guardians: [ {} ] # all guardian information
68
- # payments: [ {} ] # all payments made via openapply
69
- # }
70
- # }
71
- def student_details_by_id(id, flatten_keys=[], reject_keys=[], get_payments=true)
72
-
73
- check = check_details_keys_validity(flatten_keys, reject_keys)
74
- return check unless check.nil? # or check[:error].nil?
75
-
76
- # get full student record and guardian information
77
- student_info = student_by_id( "#{id}" )
78
- # get student payment records
79
- payment_info = payments_by_id( "#{id}" ) if get_payments.eql? true
80
-
81
- # be sure there is student data to process -- if not return an empty record
82
- return {student: {id: id, empty: []}} if student_info.nil? or
83
- student_info[:student].nil?
84
- student_info[:student].empty?
85
- student = []
86
- guardians = []
87
- # extract guardian information
88
- guardians = student_info[:linked][:parents].dup unless
89
- student_info[:linked].nil? or
90
- student_info[:linked].empty? or
91
- student_info[:linked][:parents].nil?
92
- payments = []
93
- # extract payment information
94
- payments = payment_info[:payments].dup unless payment_info.nil? or
95
- payment_info[:payments].nil?
96
- # if flatten and reject are not set - set them so they do nothing
97
- flatten_keys = [:flatten_no_keys] if flatten_keys.nil? or flatten_keys.empty?
98
- reject_keys = [:reject_no_keys] if reject_keys.nil? or reject_keys.empty?
99
-
100
- # extract the student info into the desired format (and removes \n in strings)
101
- # student = student_info[:student] - this is the effective result wo
102
- # flatten/reject keys
103
- student = flatten_record(student_info[:student], flatten_keys, reject_keys)
104
-
105
- # process guardian records - the same way student records
106
- # (loop on guardian arrary since there can be multiple parents)
107
- g_flat = []
108
- guardians = guardians.each do |guard|
109
- next if guard.empty?
110
- g_flat << flatten_record( guard, flatten_keys, reject_keys )
111
- end unless guardians.empty?
112
- guardians = g_flat unless g_flat.empty?
113
-
114
- # organize the student details
115
- return { student:
116
- { id: id,
117
- record: student,
118
- payments: payments,
119
- guardians: guardians,
120
- }
121
- }
122
- end
123
- alias_method :student_details, :student_details_by_id
124
-
125
- # UTILITIES
126
- ###########
127
-
128
- # return value & remove linebreaks & trim spaces (if a string)
129
- def clean_data( value )
130
- return value.gsub("\n",' ').strip if value.is_a? String
131
- return value
132
- end
133
-
134
- # This method preprocesses records - brings keys to the top level and
135
- # removes fields and removes \n from strings
136
- #
137
- # === Attributes
138
- # * +hash+ -- **ONE students** student_details
139
- # * +flatten_keys+ -- keys to bring to the top level (with top key prepended)
140
- # * +reject_keys+ -- remove data matching these keys
141
- # TODO: add recursion?
142
- def flatten_record(hash, flatten_keys=[:flatten_no_keys],reject_keys=[:reject_no_keys])
143
- answer = {}
144
-
145
- # loop through each key value of the student record
146
- hash.each do |key,val|
147
- # skip loop if this key matches a value to remove
148
- next if reject_keys.include? key
149
-
150
- if flatten_keys.include? key
151
- answer.merge!( flatten_key_vals(key, val, flatten_keys, reject_keys) )
152
- else
153
- # put data back into hash if not to be flattened
154
- answer[key] = clean_data(val) unless flatten_keys.include? key
155
- end
156
- end
157
-
158
- return answer
159
- end
160
-
161
-
162
-
163
- def flatten_key_vals(key, val, flatten_keys, reject_keys)
164
- if val.is_a? Array
165
- return flatten_array_vals(key, val, flatten_keys, reject_keys)
166
-
167
- elsif val.is_a? Hash
168
- return flatten_hash_vals(key, val, flatten_keys, reject_keys)
169
-
170
- else
171
- return {}
172
- end
173
-
174
- end
175
-
176
-
177
-
178
- def flatten_array_vals(key, val, flatten_keys, reject_keys)
179
- return {} if val.empty?
180
-
181
- return {}
182
- end
183
-
184
-
185
-
186
- def flatten_hash_vals(key, val, flatten_keys, reject_keys)
187
- return {} if val.empty?
188
-
189
- answer = {}
190
- # un-nest a hash a to top level keys
191
- val.each do |k,v|
192
- # remove any nested values if they match a reject_key
193
- next if reject_keys.include? k
194
-
195
- # (prepend flatten_key_to_current_key to prevent conflicts)
196
- new_key = "#{key.to_s}_#{k.to_s}".to_sym
197
- # clean the data and add back to to top level with a new key
198
- answer[new_key] = clean_data(v)
199
- end if val.is_a? Hash
200
- return answer
201
- end
202
-
203
- # Check the validity of keys to process student_details
204
- #
205
- # === Attributes
206
- # * +flatten_keys+ - is an array of symbols
207
- # * +reject_keys+ - is an array of symbols
208
- def check_details_keys_validity(flatten_keys, reject_keys)
209
- # # be sure flatten_keys are in an array
210
- return {error: "invalid flatten_keys - need array"} unless flatten_keys.is_a? Array
211
- # # be sure reject_keys are in an array
212
- return {error: "invalid reject_keys - need array"} unless reject_keys.is_a? Array
213
- # # test if any values are non-symbols (remain after removing symbols)
214
- return {error: "invalid flatten_keys - use symbols"} if flatten_keys.reject{|k| k.is_a? Symbol}.count > 0
215
- # # test if any values are non-symbols (remain after removing symbols)
216
- return {error: "invalid reject_keys - use symbols"} if reject_keys.reject{|k| k.is_a? Symbol}.count > 0
217
- end
218
-
219
- end
@@ -1,209 +0,0 @@
1
- # MULTIPLE STUDENTS API GET CALLS
2
- #################################
3
-
4
- module Get
5
-
6
- # MULTIPLE STUDENTS DETAILS (full records) - found by status (or statuses)
7
- ###########################
8
-
9
- # Returns all student details (combines student, guardian and payments records)
10
- #
11
- # === Attributes
12
- #
13
- # +flatten_keys+ - brings these keys to the top level - prepending the group name to the key name -- we usually use:
14
- # flatten_keys = [:custom_fields]
15
- # +reject keys+ -- removes the data matching these keys -- we usually use:
16
- # reject_keys = [:parent_guardian] (since this is duplicated)
17
- # * +get_payments+ - default is true (but needs double lookup) - faster when false!
18
- #
19
- # === Usage
20
- # students_details_by_status('applied')
21
- # students_details_by_status('applied', [], [],false)
22
- # students_details_by_status('applied', [:custom_fields], [:parent_guardian])
23
- # students_details_by_status('applied', [:custom_fields], [:parent_guardian], false)
24
- # students_details_by_statuses(['applied','enrolled'])
25
- # students_details_by_statuses(['applied','enrolled'], [:custom_fields], [:parent_guardian])
26
- # students_details_by_statuses(['applied','enrolled'], [:custom_fields], [:parent_guardian], false)
27
- #
28
- # === Returned Data
29
- # returns the data structured as:
30
- # { students:
31
- # [
32
- # { id: xxx, # openapply student id
33
- # record: {xxx} # complete student record
34
- # guardians: [ {xxx}, {xxx} ] # all guardian information
35
- # payments: [ {xxx}, {xxx} ] # all payments made via openapply
36
- # },
37
- # {
38
- # id: xxx, # openapply student id
39
- # record: {xxx} # complete student record
40
- # guardians: [ {xxx}, {xxx} ] # all guardian information
41
- # payments: [ {xxx}, {xxx} ] # all payments made via openapply
42
- # }
43
- # ]
44
- # }
45
- def students_details_by_status( status, flatten_keys=[], reject_keys=[], get_payments=true )
46
-
47
- check = check_details_keys_validity(flatten_keys, reject_keys)
48
- return check unless check.nil? # or check[:error].nil?
49
-
50
- ids = student_ids_by_status(status)
51
- return { error: 'answer nil' } if ids.nil?
52
- return { error: 'ids nil' } if ids[:student_ids].nil?
53
- return { students: [] } if ids[:student_ids].empty?
54
-
55
- # loop through each student
56
- error_ids = []
57
- student_records = []
58
- ids[:student_ids].each do |id|
59
- student = student_details_by_id( "#{id}", flatten_keys, reject_keys, get_payments )
60
-
61
- error_ids << id if student.nil? or
62
- student[:student].nil? or
63
- student[:student].empty?
64
- student_records << student[:student] unless student.nil? or
65
- student[:student].nil? or
66
- student[:student].empty?
67
- end
68
- return { students: student_records }
69
- end
70
- alias_method :students_details, :students_details_by_status
71
- alias_method :students_details_by_statuses, :students_details_by_status
72
-
73
- # UTILITIES FOR MULTIPLE STUDENT LOOKUPS -- using recursion
74
- ########################################
75
-
76
- # LIST OF IDS for a given STATUS
77
- ################################
78
-
79
- # returns a list of student ids that match a give status (this is recursive -
80
- # so returns the entire list - even if that list is longer than the api_return_count)
81
- #
82
- # ==== Attributes
83
- # +status+ - a **string** matching one of the OA allowed statuses **OR**
84
- # status can be an **array** of statuses (matching OA statuses)
85
- #
86
- # === Usage
87
- # student_ids_by_status('applied')
88
- # student_ids_by_statuses(['applied','enrolled'])
89
- #
90
- # === Return
91
- # {student_ids: [1, 3, 40]}
92
- # TODO: test with a mix of good and bad keys
93
- # only use good keys be sure count >= 1
94
- def student_ids_by_status(status)
95
- ids = []
96
- # when a single status is sent
97
- states = [status] if status.is_a? String
98
- states = status if status.is_a? Array
99
- states.each do |state|
100
- answer = students_by_status(state)
101
-
102
- ids += answer[:students].map{ |l| l[:id] } unless answer.nil? or
103
- answer[:students].nil? or
104
- answer[:students].empty?
105
- end
106
- return { student_ids: [] } if ids.nil? or ids.empty?
107
- return { student_ids: ids }
108
- end
109
- alias_method :all_student_ids_by_status, :student_ids_by_status
110
- alias_method :student_ids_by_statuses, :student_ids_by_status
111
-
112
- # GET STUDENT SUMMARY INFO for a given status -- mostly used to get a list of ids
113
- ##########################
114
-
115
- # Returns a list of student summaries (in OpenApply's format) that
116
- # match a give status (this is recursive - so returns the entire list -
117
- # even if that list is longer than the api_return_count)
118
- #
119
- # ==== Attributes
120
- # +status+ - **MUST BE A STRING** returns the data as is from OpenApply
121
- #
122
- # === Usage
123
- # students_by_status('applied')
124
- def students_by_status(status)
125
- url = students_custom_url(status)
126
- answer = oa_answer( url )
127
- return { error: "nil" } if answer[:students].nil?
128
- return { students: [] } if answer[:students].empty?
129
-
130
- page_number = answer[:meta][:pages]
131
- return answer if page_number == 1
132
-
133
- # inspect meta data -- loop until page = 1 (all students found)
134
- all_students = answer[:students]
135
- while page_number > 1
136
- last_student = answer[:students].last
137
- since_id = last_student[:id]
138
- url = students_custom_url(status,since_id)
139
- answer = oa_answer( url )
140
- page_number = answer[:meta][:pages]
141
- all_students += answer[:students]
142
- end
143
- return { students: all_students }
144
- end
145
- # alias_method :all_student_summaries_by_status, :students_by_status
146
- alias_method :students, :students_by_status
147
-
148
-
149
- # CUSTOM QUERIES - recursion utlities
150
- ################
151
-
152
- # Executes a custom query **(non-recursive)** to get a list of students
153
- # summaries matching the allowed attribute's criteria -- used to build
154
- # recursive or custom queries (within what is allowed by OpenApply API)
155
- #
156
- # ==== Attributes
157
- # * +status+ - match status (be sure it is in the list of OpenApply status)
158
- # * +since_id+ - get all ids matching the criteria LARGER than the given number
159
- # * +since_date+ - get all records updated after the given date (YYYY-MM-DD) or
160
- # Date and Time (YYYY-MM-DD HH:MM:SS) - 24 hour clock (not sure about timeszone)
161
- # * +count+ - return a custom number of records (no more than 1000)
162
- #
163
- # ==== Usage
164
- # students_query(nil, since_id=95, since_date=2017-01-01, count=2)
165
- #
166
- # ==== returned
167
- # { students:
168
- # [
169
- # { student summary data from openapply api },
170
- # { student summary data from openapply api },
171
- # ]
172
- # }
173
- def students_query(status=nil, since_id=nil, since_date=nil, count=api_records)
174
- return { error: "invalid count" } unless count.to_i >= 1
175
-
176
- url = students_custom_url(status, since_id, since_date, count)
177
- answer = oa_answer( url )
178
- return { error: "nil answer" } if answer.nil?
179
- return { error: "nil students" } if answer[:students].nil?
180
- return { students: [] } if answer[:students].empty?
181
- return answer
182
- end
183
- alias_method :students_custom_query, :students_query
184
-
185
- # Builds a custom url (with domain) to get a list of students summaries matching
186
- # the attribute's criteria (but not do a Query) - returns a URL
187
- #
188
- # ==== Attributes
189
- # * +status+ - match status (be sure it is in the list of OpenApply status)
190
- # * +since_id+ - get all ids matching the criteria LARGER than the given number
191
- # * +since_date+ - get all records updated after the given date (YYYY-MM-DD) or
192
- # Date and Time (YYYY-MM-DD HH:MM:SS) - 24 hour clock (not sure about timeszone)
193
- # * +count+ - return a custom number of records (no more than 1000)
194
- #
195
- # ==== Return Format
196
- # "/api/v1/students/?status=applied&since_id=96&since_date=2017-01-25&count=2&auth_token=319d9axxxxxxx"
197
- def students_query_url(status=nil, since_id=nil, since_date=nil, count=api_records)
198
- url_options = []
199
- url_options << "status=#{status}" unless status.to_s.eql? ""
200
- url_options << "since_id=#{since_id}" unless since_id.to_s.eql? ""
201
- url_options << "since_date=#{since_date}" unless since_date.to_s.eql? ""
202
- url_options << "count=#{count}"
203
- url_options << "auth_token=#{api_key}"
204
-
205
- return "#{api_path}?#{url_options.join('&')}"
206
- end
207
- alias_method :students_custom_url, :students_query_url
208
-
209
- end
@@ -1,61 +0,0 @@
1
- require 'net/scp'
2
- require 'net/ssh'
3
-
4
- # CODE THAT TRANSFORMS STUDENT DATA
5
- ###################################
6
-
7
- module SendToRemote
8
-
9
- # Send a string to convert to a file on a remote server
10
- # setup using ssh keys - not sure how to test - use at own risk
11
- #
12
- # === Attributes
13
- # * +data+ - object to be converted to a file on a remote system --
14
- # object can be a CSV String, Axlsx::Package or File object to be transfered
15
- # * +srv_hostname+ - fqdn or IP address of the remote host
16
- # * +srv_hostname+ - username to access the remote host
17
- # * +srv_path_file+ - full path and file name of the file on the remote host
18
- # * +file_permissions+ - permissions to make the file on the remote host (default is: 0750)
19
- # * +options+ - allow ssh start options to be passed in
20
- def send_data_to_remote_server( data, srv_hostname, srv_username,
21
- srv_path_file, srv_file_permissions="0750",
22
- ssl_options={}
23
- )
24
- # be sure its a file type that can be sent
25
- return "Unrecognized Object" unless known_transfer_object?(data)
26
-
27
- # Prep data as necessary for scp
28
- # https://www.safaribooksonline.com/library/view/ruby-cookbook/0596523696/ch06s15.html
29
- # convert the string to a stringio object (which can act as a file)
30
-
31
- xfer = data if data.is_a? StringIO
32
- xfer = StringIO.new( data ) if data.is_a? String
33
- xfer = data if data.is_a? File
34
-
35
- # http://www.rubydoc.info/github/delano/net-scp/Net/SCP
36
- # send the stringio object to the remote host via scp
37
- Net::SCP.start(srv_hostname, srv_username, ssl_options) do |scp|
38
- # asynchronous upload; call returns immediately
39
- channel = scp.upload( xfer, srv_path_file )
40
- channel.wait
41
- end
42
- # ensure file has desired permissions (via remote ssh command)
43
- Net::SSH.start(srv_hostname, srv_username, ssl_options) do |ssh|
44
- # Capture all stderr and stdout output from a remote process
45
- output = ssh.exec!("chmod #{srv_file_permissions} #{srv_path_file}")
46
- end
47
- end
48
- alias_method :send_string_to_server_file, :send_data_to_remote_server
49
-
50
- # Check that the data to transfer is of a known data type
51
- #
52
- # === Attributes
53
- # * +data+ - is it an Axlsx::Package, Sting, StringIO or a File class?
54
- def known_transfer_object?( data )
55
- return true if data.is_a? StringIO
56
- return true if data.is_a? String
57
- return true if data.is_a? File
58
- return false
59
- end
60
-
61
- end