openapply 0.2.10 → 0.3.0

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.
@@ -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