openapply 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|