openapply 0.2.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/README.md +165 -387
- data/examples/demo/README.md +74 -18
- data/examples/demo/demo_site.rb +40 -74
- data/lib/openapply/convert.rb +371 -0
- data/lib/openapply/get_student.rb +125 -223
- data/lib/openapply/get_students.rb +143 -340
- data/lib/openapply/version.rb +1 -1
- data/lib/openapply.rb +12 -8
- data/openapply.gemspec +5 -0
- metadata +59 -3
- data/examples/demo/.rbenv-vars +0 -5
data/examples/demo/README.md
CHANGED
@@ -10,15 +10,11 @@ pry
|
|
10
10
|
|
11
11
|
and run this code (or play )
|
12
12
|
```ruby
|
13
|
-
require 'pp'
|
14
13
|
require 'openapply'
|
15
|
-
require_relative './demo_site'
|
16
|
-
|
17
14
|
|
18
15
|
# BASIC USAGE (see readme)
|
19
16
|
# use the .rbenv-vars for a simple setup
|
20
17
|
@oa = Openapply::Client.new()
|
21
|
-
@oa.one_student_record_by_id(95)
|
22
18
|
|
23
19
|
# see settings
|
24
20
|
@oa.api_url
|
@@ -26,31 +22,91 @@ require_relative './demo_site'
|
|
26
22
|
@oa.base_path
|
27
23
|
@oa.api_timeout
|
28
24
|
@oa.api_reply_count
|
29
|
-
|
30
|
-
|
25
|
+
|
26
|
+
|
27
|
+
# student summarys with applied status
|
28
|
+
summaries = @oa.students_by_status('applied')
|
29
|
+
student_ids = @oa.student_ids_by_status('applied')
|
30
|
+
|
31
|
+
ids = student_ids[:student_ids]
|
32
|
+
|
33
|
+
|
34
|
+
# first student details - return data as is
|
35
|
+
details = @oa.student_details_by_id(ids.first)
|
36
|
+
|
37
|
+
# last applied student details - custom fields -
|
38
|
+
# top level & duplicate :parent removed
|
39
|
+
flattened = @oa.student_details_by_id(ids.last, [:custom_fields], [:parent_guardian])
|
40
|
+
|
41
|
+
# get first 5 records with status applied with student_ids greater than the last
|
42
|
+
# two records (which should return last six students) - but response is limited to 5
|
43
|
+
# updated after 5th of Nov 2016
|
44
|
+
custom = @oa.students_query('applied', ids[-7] , '2016-11-05', 5)
|
45
|
+
|
46
|
+
|
47
|
+
# get students with applied and enrolled status, flatten no fields,
|
48
|
+
# remove the parent_guardian (duplicate) info,
|
49
|
+
# move into the xlsx file the following data: studnet id and student name
|
50
|
+
# parent address (line 1) and country, and no payment info
|
51
|
+
csv = @oa.students_as_csv_by_status( 'applied', nil, [:parent_guardian],
|
52
|
+
[:id, :name], {keys: [:address, :country]}, nil )
|
53
|
+
#
|
54
|
+
@oa.send_data_to_remote_server( csv, ENV['REMOTE_HOSTNAME'],
|
55
|
+
ENV['REMOTE_USERNAME'], "#{ENV['REMOTE_PATH_FILE']}.csv", ENV['REMOTE_PERMISSIONS'])
|
56
|
+
# save csv string as a file locally
|
57
|
+
open('test_file.csv', 'w') { |f| f.puts csv }
|
58
|
+
|
59
|
+
# get students with applied and enrolled status, flatten the custom_fields,
|
60
|
+
# remove the parent_guardian (duplicate) info,
|
61
|
+
# move into the xlsx file the following data: studnet id and student name
|
62
|
+
# parent address (line 1) and country, and the oldest three payment amounts & dates
|
63
|
+
xlsx = @oa.students_as_xlsx_by_status(['applied','accepted'], [:custom_fields],
|
64
|
+
[:parent_guardian], [:id, :name],
|
65
|
+
{count: 2, keys: [:address, :country]},
|
66
|
+
{count: , order: :oldest, keys: [:amount, :date]})
|
67
|
+
#
|
68
|
+
@oa.send_data_to_remote_server( xlsx, ENV['REMOTE_HOSTNAME'],
|
69
|
+
ENV['REMOTE_USERNAME'], "#{ENV['REMOTE_PATH_FILE']}.xlsx", ENV['REMOTE_PERMISSIONS'])
|
70
|
+
# save as a xlsx file locally
|
71
|
+
xlsx.serialize('test_file.xlsx')
|
72
|
+
|
31
73
|
```
|
32
74
|
|
33
75
|
* or More advanced - multiple OA sites
|
34
76
|
```ruby
|
35
77
|
|
36
|
-
require 'pp'
|
78
|
+
# require 'pp'
|
37
79
|
require 'openapply'
|
38
80
|
require_relative './demo_site'
|
39
81
|
|
40
82
|
# use a class override in order to interact with multiple oa sites
|
41
|
-
|
83
|
+
# or extend functionality
|
84
|
+
@mine = MySite.new()
|
85
|
+
|
86
|
+
|
87
|
+
# get students with applied and enrolled status, flatten no fields,
|
88
|
+
# remove the parent_guardian (duplicate) info,
|
89
|
+
# move into the xlsx file the following data: studnet id and student name
|
90
|
+
# parent address (line 1) and country, and no payment info
|
91
|
+
@mine.records_as_csv_to_file( 'applied', nil, [:parent_guardian], [:id, :name],
|
92
|
+
{keys: [:address, :country]}, nil , 'test.csv' )
|
42
93
|
|
43
|
-
|
44
|
-
|
94
|
+
@mine.records_as_csv_to_server( 'applied', nil, [:parent_guardian], [:id, :name],
|
95
|
+
{keys: [:address, :country]}, nil )
|
45
96
|
|
46
|
-
# get
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
97
|
+
# get students with applied and enrolled status, flatten the custom_fields,
|
98
|
+
# remove the parent_guardian (duplicate) info,
|
99
|
+
# move into the xlsx file the following data: studnet id and student name
|
100
|
+
# parent address (line 1) and country, and the oldest three payment amounts & dates
|
101
|
+
@mine.records_as_xlsx_to_file( ['applied','enrolled'], [:custom_fields],
|
102
|
+
[:parent_guardian], [:id, :name],
|
103
|
+
{count: 2, keys: [:address, :country]},
|
104
|
+
{count: 3, order: :oldest, keys: [:amount, :date]}, 'test.xlsx')
|
51
105
|
|
52
|
-
|
53
|
-
|
54
|
-
|
106
|
+
@mine.records_as_xlsx_to_server(['applied','enrolled'], [:custom_fields],
|
107
|
+
[:parent_guardian], [:id, :name],
|
108
|
+
{count: 2, keys: [:address, :country]},
|
109
|
+
{count: 3, order: :newest, keys: [:amount, :date]})
|
55
110
|
|
111
|
+
# use cron or other similar tools to automate these processes
|
56
112
|
```
|
data/examples/demo/demo_site.rb
CHANGED
@@ -1,94 +1,60 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'csv'
|
4
|
-
require 'net/scp'
|
5
|
-
require 'stringio'
|
6
3
|
require 'httparty'
|
7
4
|
|
8
|
-
class
|
5
|
+
class MySite < Openapply::Client
|
9
6
|
include HTTParty
|
10
7
|
|
11
|
-
#
|
12
|
-
|
8
|
+
# add customized site info
|
9
|
+
# (say you need to use both: demo.openapply.com and my.openapply.com) --
|
10
|
+
# this class defines my.openapply.com and its special needs
|
11
|
+
localized_url = ENV['MY_BASE_URI']
|
13
12
|
base_uri localized_url
|
14
13
|
|
15
14
|
def api_key
|
16
|
-
ENV['
|
15
|
+
ENV['MY_AUTH_TOKEN']
|
17
16
|
end
|
18
17
|
|
19
|
-
#
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
18
|
+
# defines remote host to recieve openapply data
|
19
|
+
REMOTE_HOSTNAME = ENV['REMOTE_HOSTNAME'].freeze
|
20
|
+
REMOTE_USERNAME = ENV['REMOTE_USERNAME'].freeze
|
21
|
+
REMOTE_PATH_FILE = ENV['REMOTE_PATH_FILE'].freeze
|
22
|
+
REMOTE_PERMISSIONS = ENV['REMOTE_PERMISSIONS'].freeze
|
23
|
+
|
24
|
+
# custom code to prepare my.openapply.com data for remote host recieving data
|
25
|
+
def records_as_csv_to_file( status, flatten_keys=[],
|
26
|
+
reject_keys=[], student_keys=[],
|
27
|
+
guardian_info={}, payment_info={}, file )
|
28
|
+
data = students_as_csv_by_status( status, flatten_keys, reject_keys,
|
29
|
+
student_keys, guardian_info, payment_info)
|
30
|
+
# save csv string as a file
|
31
|
+
open(file, 'w') { |f| f.puts data }
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
array << headers
|
43
|
-
|
44
|
-
# don't loop if hash is empty
|
45
|
-
return headers if hash.empty?
|
46
|
-
|
47
|
-
hash[:students].each do |record|
|
48
|
-
row = []
|
49
|
-
# skip record if empty
|
50
|
-
# puts "#{record[:record]}\n"
|
51
|
-
next if record.nil?
|
52
|
-
next if record.nil?
|
53
|
-
next if record.empty?
|
54
|
-
|
55
|
-
# find the desired fields and add them to the csv
|
56
|
-
csv_keys.each{ |key| row << record[key] }
|
57
|
-
|
58
|
-
# add row to the master arrary
|
59
|
-
array << row
|
60
|
-
end
|
61
|
-
return array
|
34
|
+
def records_as_csv_to_server( status, flatten_keys=[],
|
35
|
+
reject_keys=[], student_keys=[],
|
36
|
+
guardian_info={}, payment_info={})
|
37
|
+
data = students_as_csv_by_status( status, flatten_keys, reject_keys,
|
38
|
+
student_keys, guardian_info, payment_info)
|
39
|
+
send_data_to_remote_server( data, REMOTE_HOSTNAME, REMOTE_USERNAME,
|
40
|
+
"#{REMOTE_PATH_FILE}.csv", REMOTE_PERMISSIONS)
|
62
41
|
end
|
63
42
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
csv << row
|
71
|
-
end
|
72
|
-
end
|
73
|
-
return csv_string
|
43
|
+
def records_as_xlsx_to_file( status, flatten_keys=[],
|
44
|
+
reject_keys=[], student_keys=[],
|
45
|
+
guardian_info={}, payment_info={}, file )
|
46
|
+
data = students_as_xlsx_by_status( status, flatten_keys, reject_keys,
|
47
|
+
student_keys, guardian_info, payment_info)
|
48
|
+
data.serialize(file)
|
74
49
|
end
|
75
50
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
# asynchronous upload; call returns immediately
|
84
|
-
channel = scp.upload( xfer_csv, remote_path_n_file )
|
85
|
-
channel.wait
|
86
|
-
end
|
87
|
-
# ensure file has proper permissions
|
88
|
-
Net::SSH.start(host_name, user_name) do |ssh|
|
89
|
-
# Capture all stderr and stdout output from a remote process
|
90
|
-
output = ssh.exec!("chmod 0775 #{remote_path_n_file}")
|
91
|
-
end
|
51
|
+
def records_as_xlsx_to_server( status, flatten_keys=[],
|
52
|
+
reject_keys=[], student_keys=[],
|
53
|
+
guardian_info={}, payment_info={})
|
54
|
+
data = students_as_xlsx_by_status( status, flatten_keys, reject_keys,
|
55
|
+
student_keys, guardian_info, payment_info)
|
56
|
+
send_data_to_remote_server( data, REMOTE_HOSTNAME, REMOTE_USERNAME,
|
57
|
+
"#{REMOTE_PATH_FILE}.xlsx", REMOTE_PERMISSIONS)
|
92
58
|
end
|
93
59
|
|
94
60
|
end
|
@@ -0,0 +1,371 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'axlsx'
|
3
|
+
require 'net/scp'
|
4
|
+
require 'net/ssh'
|
5
|
+
|
6
|
+
module Convert
|
7
|
+
|
8
|
+
# Queries by status to get a list of students details of a given status
|
9
|
+
# and converts the result to an array with headers (based on keys sent)
|
10
|
+
#
|
11
|
+
# ==== Attributes
|
12
|
+
# * +status+ - hash to convert to an array
|
13
|
+
# * +flatten_keys+ - an array of keys to bring to the top level
|
14
|
+
# (with this key prepened) -- default (blank does nothing)
|
15
|
+
# * +reject_keys+ - an array of keys to remove from the data -- default (blank does nothing)
|
16
|
+
# * +student_keys+ - [:id, :name] - include student record keys
|
17
|
+
# * +guardian_info+ - include guardian record info {count: 2, keys: [:id, :name]}
|
18
|
+
# * +payment_info+ - include payment info {count: 2, order: :newest, keys: [:date, :amount]}
|
19
|
+
# * guardian & payment info options:
|
20
|
+
# count: 2 -- how many parent or payment records to return)
|
21
|
+
# keys: [:id, :date] -- an array of keys of data to return
|
22
|
+
# order: :newest -- the order to return payments :newest (most recent first - default) or :oldest
|
23
|
+
def students_as_array_by_status(status,
|
24
|
+
flatten_keys=[], reject_keys=[],
|
25
|
+
student_keys=[],
|
26
|
+
guardian_info={}, payment_info={})
|
27
|
+
#
|
28
|
+
check = check_details_keys_validity(flatten_keys, reject_keys)
|
29
|
+
return check unless check.nil? # or check[:error].nil?
|
30
|
+
#
|
31
|
+
students_hash = students_details_by_status( status,
|
32
|
+
flatten_keys, reject_keys)
|
33
|
+
#
|
34
|
+
students_array = students_hash_to_array( students_hash,
|
35
|
+
student_keys, guardian_info, payment_info)
|
36
|
+
end
|
37
|
+
alias_method :students_as_array_by_statuses, :students_as_array_by_status
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
# CSV CODE
|
42
|
+
##########
|
43
|
+
|
44
|
+
# Queries by status to get a list of students details of a given status
|
45
|
+
# and converts the result to a CSV string with headers (based on keys sent)
|
46
|
+
#
|
47
|
+
# ==== Attributes
|
48
|
+
# * +status+ - hash to convert to an array
|
49
|
+
# * +flatten_keys+ - an array of keys to bring to the top level
|
50
|
+
# (with this key prepened) -- default (blank does nothing)
|
51
|
+
# * +reject_keys+ - an array of keys to remove from the data -- default (blank does nothing)
|
52
|
+
# * +student_keys+ - [:id, :name] - include student record keys
|
53
|
+
# * +guardian_info+ - include guardian record info {count: 2, keys: [:id, :name]}
|
54
|
+
# * +payment_info+ - include payment info {count: 2, order: :newest, keys: [:date, :amount]}
|
55
|
+
# * guardian & payment info options:
|
56
|
+
# count: 2 -- how many parent or payment records to return)
|
57
|
+
# keys: [:id, :date] -- an array of keys of data to return
|
58
|
+
# order: :newest -- the order to return payments :newest (most recent first - default) or :oldest
|
59
|
+
def students_as_csv_by_status( status,
|
60
|
+
flatten_keys=[], reject_keys=[],
|
61
|
+
student_keys=[],
|
62
|
+
guardian_info={}, payment_info={})
|
63
|
+
#
|
64
|
+
check = check_details_keys_validity(flatten_keys, reject_keys)
|
65
|
+
return check unless check.nil? # or check[:error].nil?
|
66
|
+
# check = check_header_keys_validity(student_keys, guardian_info, payment_info)
|
67
|
+
# return check unless check.nil?
|
68
|
+
#
|
69
|
+
students_array = students_as_array_by_status( status,
|
70
|
+
flatten_keys, reject_keys,
|
71
|
+
student_keys, guardian_info, payment_info )
|
72
|
+
#
|
73
|
+
return students_array if students_array.is_a? Hash
|
74
|
+
#
|
75
|
+
student_csv_txt = students_array_to_csv( students_array )
|
76
|
+
end
|
77
|
+
alias_method :students_as_csv_by_statuses, :students_as_csv_by_status
|
78
|
+
|
79
|
+
# Given an array convert to CSV string
|
80
|
+
#
|
81
|
+
# ==== Attributes
|
82
|
+
# +array+ - expects a hash of students_details (should be flattened to use custom fields)
|
83
|
+
def students_array_to_csv(array)
|
84
|
+
return "" if array.nil? or array.empty?
|
85
|
+
# https://stackoverflow.com/questions/4822422/output-array-to-csv-in-ruby
|
86
|
+
csv_string = CSV.generate do |csv|
|
87
|
+
array.each do |row|
|
88
|
+
csv << row
|
89
|
+
end
|
90
|
+
end
|
91
|
+
return csv_string
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
# XLSX CODE
|
96
|
+
###########
|
97
|
+
|
98
|
+
|
99
|
+
# Queries by status to get a list of students details of a given status
|
100
|
+
# and converts the result to a XLSX Object (Axlsx::Package) with headers
|
101
|
+
# (based on keys sent)
|
102
|
+
#
|
103
|
+
# ==== Attributes
|
104
|
+
# * +status+ - hash to convert to an array
|
105
|
+
# * +flatten_keys+ - an array of keys to bring to the top level
|
106
|
+
# (with this key prepened) -- default (blank does nothing)
|
107
|
+
# * +reject_keys+ - an array of keys to remove from the data -- default (blank does nothing)
|
108
|
+
# * +student_keys+ - [:id, :name] - include student record keys
|
109
|
+
# * +guardian_info+ - include guardian record info {count: 2, keys: [:id, :name]}
|
110
|
+
# * +payment_info+ - include payment info {count: 2, order: :newest, keys: [:date, :amount]}
|
111
|
+
# * guardian & payment info options:
|
112
|
+
# count: 2 -- how many parent or payment records to return)
|
113
|
+
# keys: [:id, :date] -- an array of keys of data to return
|
114
|
+
# order: :newest -- the order to return payments :newest (most recent first - default) or :oldest
|
115
|
+
def students_as_xlsx_by_status( status,
|
116
|
+
flatten_keys=[], reject_keys=[],
|
117
|
+
student_keys=[],
|
118
|
+
guardian_info={}, payment_info={})
|
119
|
+
#
|
120
|
+
check = check_details_keys_validity(flatten_keys, reject_keys)
|
121
|
+
return check unless check.nil? # or check[:error].nil?
|
122
|
+
# check = check_header_keys_validity(student_keys, guardian_info, payment_info)
|
123
|
+
# return check unless check.nil?
|
124
|
+
#
|
125
|
+
students_array = students_as_array_by_status( status,
|
126
|
+
flatten_keys, reject_keys,
|
127
|
+
student_keys, guardian_info, payment_info )
|
128
|
+
#
|
129
|
+
return students_array if students_array.is_a? Hash
|
130
|
+
#
|
131
|
+
students_xlsx = students_array_to_xlsx( students_array )
|
132
|
+
|
133
|
+
# example how to save the xlsx object as a file
|
134
|
+
# students_xlsx.serialize("spec/data/xlsx/students_from_oa.xlsx")
|
135
|
+
|
136
|
+
return students_xlsx
|
137
|
+
end
|
138
|
+
alias_method :students_as_xlsx_by_statuses, :students_as_xlsx_by_status
|
139
|
+
|
140
|
+
|
141
|
+
# Given an array convert to XLSX Object (Axlsx::Package)
|
142
|
+
#
|
143
|
+
# ==== Attributes
|
144
|
+
# +array+ - expects a hash of students_details (should be flattened to use custom fields)
|
145
|
+
def students_array_to_xlsx(student_array)
|
146
|
+
xlsx_obj = Axlsx::Package.new do |p|
|
147
|
+
p.workbook.add_worksheet(:name => "Students from OpenApply") do |sheet|
|
148
|
+
student_array.each{ |r| sheet.add_row r }
|
149
|
+
end
|
150
|
+
# to save the xlsx object as a file
|
151
|
+
# p.serialize("spec/data/xlsx/students_from_oa.xlsx")
|
152
|
+
end
|
153
|
+
return xlsx_obj
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# ARRAY CODE
|
158
|
+
############
|
159
|
+
|
160
|
+
# Given an hash of students_details converts to an arrary
|
161
|
+
#
|
162
|
+
# ==== Attributes
|
163
|
+
# * +students+ - hash to convert to an array
|
164
|
+
# * +student_keys+ - [:id, :name] - include student record keys
|
165
|
+
# * +guardian_info+ - include guardian record info {count: 2, keys: [:id, :name]}
|
166
|
+
# * +payment_info+ - include payment info {count: 2, order: :newest, keys: [:date, :amount]}
|
167
|
+
# * guardian & payment info options:
|
168
|
+
# count: 2 -- how many parent or payment records to return)
|
169
|
+
# keys: [:id, :date] -- an array of keys of data to return
|
170
|
+
# order: :newest -- the order to return payments :newest (most recent first - default) or :oldest
|
171
|
+
def students_hash_to_array(students, student_keys=[], guardian_info={}, payment_info={})
|
172
|
+
|
173
|
+
check = check_header_keys_validity(student_keys, guardian_info, payment_info)
|
174
|
+
return check unless check.nil?
|
175
|
+
|
176
|
+
array = []
|
177
|
+
array << create_headers( student_keys, guardian_info, payment_info )
|
178
|
+
return array if students.nil? or students.empty?
|
179
|
+
|
180
|
+
students[:students].each do |student|
|
181
|
+
row = []
|
182
|
+
|
183
|
+
# next if student.nil? or student.empty? or
|
184
|
+
# student[:record].nil? or student[:record].empty?
|
185
|
+
|
186
|
+
kid_record = student[:record]
|
187
|
+
guardians = student[:guardians]
|
188
|
+
payments = student[:payments]
|
189
|
+
|
190
|
+
# inject student record info into the array
|
191
|
+
student_keys.each{ |key| row << kid_record[key] }
|
192
|
+
|
193
|
+
# inject guardian record info into the array
|
194
|
+
if process_key_info?(guardian_info)
|
195
|
+
count = info_count(guardian_info).to_i - 1
|
196
|
+
# loop through the correct number of parents
|
197
|
+
(0..count).each do |i|
|
198
|
+
# add info if parent record exists
|
199
|
+
guardian_info[:keys].each{ |key| row << guardians[i][key] } if guardians[i]
|
200
|
+
# add nils if there isn't a parent record
|
201
|
+
guardian_info[:keys].each{ |key| row << nil } unless guardians[i]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
# inject guardian record info (most recent - last to oldest) into the array
|
206
|
+
if process_key_info?(payment_info)
|
207
|
+
if payment_info[:order].nil? or payment_info[:order].eql? :newest
|
208
|
+
# get the newest records first
|
209
|
+
count = info_count(payment_info).to_i
|
210
|
+
# loop through the correct number of parents
|
211
|
+
(1..count).each do |index|
|
212
|
+
i = index * -1
|
213
|
+
# puts "INDEX #{i}"
|
214
|
+
payment_info[:keys].each{ |key| row << payments[i][key] } if payments[i]
|
215
|
+
payment_info[:keys].each{ |key| row << nil } unless payments[i]
|
216
|
+
end
|
217
|
+
else
|
218
|
+
# start with the oldest records
|
219
|
+
count = info_count(payment_info).to_i - 1
|
220
|
+
# loop through the correct number of parents
|
221
|
+
(0..count).each do |i|
|
222
|
+
payment_info[:keys].each{ |key| row << payments[i][key] } if payments[i]
|
223
|
+
payment_info[:keys].each{ |key| row << nil } unless payments[i]
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
array << row
|
228
|
+
end
|
229
|
+
return array
|
230
|
+
end
|
231
|
+
|
232
|
+
# internal key to process given info or not
|
233
|
+
def process_key_info?(info)
|
234
|
+
return true unless info.nil? or info.empty? or
|
235
|
+
info[:keys].nil? or info[:keys].empty?
|
236
|
+
return false
|
237
|
+
end
|
238
|
+
|
239
|
+
# determine count - may extend later to self-discover max number of records
|
240
|
+
def info_count(info)
|
241
|
+
info[:count] || 1
|
242
|
+
end
|
243
|
+
|
244
|
+
# Given the parameters passed in create the create csv / arrary headers
|
245
|
+
#
|
246
|
+
# ==== Attributes
|
247
|
+
# * +students+ - hash to convert to an array
|
248
|
+
# * +student_keys+ - include student record keys
|
249
|
+
# * +guardian_info+ - include guardian record info {count: 2, keys: [:id, :name]}
|
250
|
+
# * +payment_info+ - include payment info {count: 2, order: :newest, keys: [:date, :amount]}
|
251
|
+
# * guardian & payment info options:
|
252
|
+
# count: 2 -- how many parent or payment records to return)
|
253
|
+
# keys: [:id, :date] -- an array of keys of data to return
|
254
|
+
# order: :newest -- the order to return payments :newest (most recent first - default) or :oldest
|
255
|
+
def create_headers( student_keys=[], guardian_info={}, payment_info={} )
|
256
|
+
headers = []
|
257
|
+
# figure out student headers
|
258
|
+
student_keys = [:id] if student_keys.nil? or student_keys.empty?
|
259
|
+
headers = student_keys.map{ |k| "student_" + k.to_s }
|
260
|
+
# figure out guardian headers
|
261
|
+
if process_key_info?(guardian_info)
|
262
|
+
guardian_count = info_count(guardian_info)
|
263
|
+
# add the correct headers
|
264
|
+
(1..guardian_count).each do |i|
|
265
|
+
headers += guardian_info[:keys].map{|k| "guardian#{i}_" + k.to_s }
|
266
|
+
end
|
267
|
+
end
|
268
|
+
# calculate payment headers
|
269
|
+
if process_key_info?(payment_info)
|
270
|
+
payment_count = info_count(payment_info)
|
271
|
+
# add the correct headers
|
272
|
+
(1..payment_count).each do |i|
|
273
|
+
headers += payment_info[:keys].map{|k| "payment#{i}_" + k.to_s }
|
274
|
+
end
|
275
|
+
end
|
276
|
+
return headers
|
277
|
+
end
|
278
|
+
|
279
|
+
# XFER CODE
|
280
|
+
###########
|
281
|
+
|
282
|
+
# Send a string to convert to a file on a remote server
|
283
|
+
# setup using ssh keys - not sure how to test - use at own risk
|
284
|
+
#
|
285
|
+
# === Attributes
|
286
|
+
# * +data+ - object to be converted to a file on a remote system --
|
287
|
+
# object can be a CSV String, Axlsx::Package or File object to be transfered
|
288
|
+
# * +srv_hostname+ - fqdn or IP address of the remote host
|
289
|
+
# * +srv_hostname+ - username to access the remote host
|
290
|
+
# * +srv_path_file+ - full path and file name of the file on the remote host
|
291
|
+
# * +file_permissions+ - permissions to make the file on the remote host (default is: 0750)
|
292
|
+
def send_data_to_remote_server( data, srv_hostname, srv_username,
|
293
|
+
srv_path_file, file_permissions='0750')
|
294
|
+
# https://www.safaribooksonline.com/library/view/ruby-cookbook/0596523696/ch06s15.html
|
295
|
+
# convert the string to a stringio object (which can act as a file)
|
296
|
+
|
297
|
+
# just move the file via SCP
|
298
|
+
xfer = data if data.is_a? File
|
299
|
+
# convert string into a SteamIO - "FILE" like object
|
300
|
+
xfer = data if data.is_a? StringIO
|
301
|
+
# convert string into a SteamIO - "FILE" like object
|
302
|
+
xfer = StringIO.new( data ) if data.is_a? String
|
303
|
+
# convert Axlsx object into a SteamIO - "FILE" like object
|
304
|
+
xfer = data.to_stream() if data.is_a? Axlsx::Package
|
305
|
+
|
306
|
+
# be sure its a file type that can be sent
|
307
|
+
return "Unrecognized Object" unless known_transfer_object?(data)
|
308
|
+
|
309
|
+
# http://www.rubydoc.info/github/delano/net-scp/Net/SCP
|
310
|
+
# send the stringio object to the remote host via scp
|
311
|
+
Net::SCP.start(srv_hostname, srv_username) do |scp|
|
312
|
+
# asynchronous upload; call returns immediately
|
313
|
+
channel = scp.upload( xfer, srv_path_file )
|
314
|
+
channel.wait
|
315
|
+
end
|
316
|
+
# ensure file has desired permissions (via remote ssh command)
|
317
|
+
Net::SSH.start(srv_hostname, srv_username) do |ssh|
|
318
|
+
# Capture all stderr and stdout output from a remote process
|
319
|
+
output = ssh.exec!("chmod #{file_permissions} #{srv_path_file}")
|
320
|
+
end
|
321
|
+
end
|
322
|
+
alias_method :send_string_to_server_file, :send_data_to_remote_server
|
323
|
+
|
324
|
+
# Check that the data to transfer is of a known data type
|
325
|
+
#
|
326
|
+
# === Attributes
|
327
|
+
# * +data+ - is it an Axlsx::Package, Sting, StringIO or a File class?
|
328
|
+
def known_transfer_object?( data )
|
329
|
+
return true if data.is_a? String or data.is_a? Axlsx::Package or
|
330
|
+
data.is_a? File or data.is_a? StringIO
|
331
|
+
return false
|
332
|
+
end
|
333
|
+
|
334
|
+
# Check header info before processing
|
335
|
+
#
|
336
|
+
# === Attributes
|
337
|
+
# * +student_keys+ - that this is an arrary of symbols
|
338
|
+
# * +guardian_info+ - that this is a hash with keys: using symbols
|
339
|
+
# * +payment_info+ - that this is a hash with keys: using symbols
|
340
|
+
def check_header_keys_validity(student_keys, guardian_info, payment_info)
|
341
|
+
# prepare keys for testing
|
342
|
+
student_keys ||= []
|
343
|
+
#
|
344
|
+
#
|
345
|
+
guardian_info ||= {}
|
346
|
+
return {error: "invalid guardian_info - use hash"} unless guardian_info.is_a? Hash
|
347
|
+
guardian_keys = guardian_info[:keys] #unless guardian_keys[:keys].nil?
|
348
|
+
guardian_keys ||= []
|
349
|
+
#
|
350
|
+
payment_info ||= {}
|
351
|
+
return {error: "invalid payment_info - use hash"} unless payment_info.is_a? Hash
|
352
|
+
payment_keys = payment_info[:keys] #unless payment_keys[:keys].nil?
|
353
|
+
payment_keys ||= []
|
354
|
+
|
355
|
+
# be sure keys are in an array
|
356
|
+
return {error: "invalid student_keys - need array"} unless student_keys.is_a? Array
|
357
|
+
return {error: "invalid guardian_keys - need array"} unless guardian_keys.is_a? Array
|
358
|
+
return {error: "invalid payment_keys - need array"} unless payment_keys.is_a? Array
|
359
|
+
|
360
|
+
# test if any key values are non-symbols (remain after removing symbols)
|
361
|
+
return {error: "invalid student_keys - use symbols"} if student_keys.reject{|k| k.is_a? Symbol}.count > 0
|
362
|
+
return {error: "invalid guardian_keys - use symbols"} if guardian_keys.reject{|k| k.is_a? Symbol}.count > 0
|
363
|
+
return {error: "invalid payment_keys - use symbols"} if payment_keys.reject{|k| k.is_a? Symbol}.count > 0
|
364
|
+
|
365
|
+
# check that if guardian info is given - it also has keys
|
366
|
+
return {error: "invalid guardian_keys - keys missing"} if not guardian_info.empty? and guardian_info[:keys].nil?
|
367
|
+
return {error: "invalid payment_keys - keys missing"} if not payment_info.empty? and payment_info[:keys].nil?
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|