banner_jobsub 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.rubocop.yml +2 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +62 -0
- data/Rakefile +6 -0
- data/banner_jobsub.gemspec +29 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/examples/gyrruby +64 -0
- data/examples/gyrruby.yaml +2 -0
- data/examples/gyrruby_install.sql +60 -0
- data/examples/gyrschd +108 -0
- data/examples/gyrschd.erb +8 -0
- data/examples/gyrschd_install.sql +50 -0
- data/lib/banner_jobsub.rb +176 -0
- data/lib/banner_jobsub/version.rb +3 -0
- metadata +133 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: df57c1542ec9b65a18d69277acff4532f7321f37
|
4
|
+
data.tar.gz: 91376a193944767c887246875147a1b7ea10dc5e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 43f6b664559d7dda8e1c659ec7d6b0c29f0a3bd8ce157f518e51c4a27ada69af550b598c84ee5e540636200a665fc973c7f43b380c5713aa0baecd86959e5f99
|
7
|
+
data.tar.gz: 50154f10def84f5f97a14d5c854e0284ed20029e31ef7abddfb641c56e6ebb1320826afb6a338ce5a700660aedea3f66503e05c0b3229428243ef51154b24614
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ian Dillon
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# BannerJobsub
|
2
|
+
|
3
|
+
BannerJobsub is a Ruby gem that makes it easy to write Banner jobsub programs in Ruby instead of Pro*C. Increased readability, maintainability, and usefulness plus it gets you the power and flexibility of Ruby's standard library and available gems. By default, BannerJobsub will perform basic boilerplate operations for your job:
|
4
|
+
- Creates an oci8 database connection, including validating/applying Banner security.
|
5
|
+
- Creates output `.lis` file and swaps `STDOUT` to it, also provides `#log` file handle to write to logfile.
|
6
|
+
- Fetches submitted GJBPRUN parameter values into named hash.
|
7
|
+
- Provides default header / footer for formatr output.
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
Using `gem` on your jobsub server:
|
11
|
+
```
|
12
|
+
gem install banner_jobsub
|
13
|
+
```
|
14
|
+
|
15
|
+
## Requirements
|
16
|
+
- [Ruby](https://www.ruby-lang.org/en/documentation/installation/) >= 2.1.0
|
17
|
+
- [ruby-oci8](https://rubygems.org/gems/ruby-oci8) >= 2.2.1
|
18
|
+
- [formatr](https://rubygems.org/gems/formatr) >= 1.10.1
|
19
|
+
|
20
|
+
## Configuration
|
21
|
+
BannerJobsub expects standard/global configuration values configuration values to be stored in `$BANNER_HOME/admin/banner_jobsub.yaml`. Basic, minimum required values are your SEED1 and SEED3 values:
|
22
|
+
```yaml
|
23
|
+
seed_one: 111111111
|
24
|
+
seed_three: 22222222
|
25
|
+
```
|
26
|
+
More options and configuration values are covered below.
|
27
|
+
|
28
|
+
## Installing a Job
|
29
|
+
Setting up a Ruby program to run via jobsub / INB GJAPCTL is basically the same a compiled Pro*C:
|
30
|
+
1. Create necessary job and security entries in Banner (GJBJOBS, GJBPDEF, etc) like a normal Pro*C job.
|
31
|
+
2. Place Ruby program _without an extension_ ("gyrruby" in this example) in `$BANNER_HOME/general/exe` (or symlink it there from the appropriate "mods" directory, up to you).
|
32
|
+
3. Set the executable bit on the program:`chmod +x $BANNER_HOME/general/exe/gyrruby`
|
33
|
+
|
34
|
+
## Examples
|
35
|
+
A few examples are provided in the `examples/` directory. Basic usage is covered in [examples/gyrruby](examples/gyrruby).
|
36
|
+
|
37
|
+
## Developing with BannerJobsub
|
38
|
+
BannerJobsub tries to make the development phase a little less painful by providing a a couple of convenience features when running a job from the command line.
|
39
|
+
|
40
|
+
**Credentials**: BannerJobsub will never prompt for username/password database credentials. Instead, it expects username and password to be provided in `~/.banner_jobsub`:
|
41
|
+
```yaml
|
42
|
+
username: scott
|
43
|
+
password: tiger
|
44
|
+
```
|
45
|
+
|
46
|
+
**Parameters**: To make repeated debugging/testing runs easier, BannerJobsub will look for `jobname.yaml` (ex: `gyrruby.yaml`, `syrblah.yaml`, etc) in the current directory and load matching parameter values from it.
|
47
|
+
|
48
|
+
So for this declaration in `gyrruby`:
|
49
|
+
```ruby
|
50
|
+
require 'banner_jobsub'
|
51
|
+
@env = BannerJobsub::Base.new(name: "GYRRUBY", params: [:start_date, :end_date])
|
52
|
+
```
|
53
|
+
|
54
|
+
BannerJobsub will look for `gyrruby.yaml` in the current directory to load parameter values:
|
55
|
+
```yaml
|
56
|
+
start_date: 01-JAN-2015
|
57
|
+
end_date: 31-DEC-2015
|
58
|
+
```
|
59
|
+
|
60
|
+
If not found, BannerJobsub will prompt for each parameter in turn. Multi-value parameters should be separated by a comma.
|
61
|
+
|
62
|
+
**Output Formatting**: BannerJobsub suggests using [formatr](https://rubygems.org/gems/formatr) for tabular/fixed output formatting, as it provides "visual" layouts (perlform, essentially). Much easier than using `table(...)` based formatting. `BannerJobsub::Base#print_header` and `BannerJobsub::Base#print_footer` provide simple page header/footer outputs. More information can found at the [formatr docs](http://www.rubydoc.info/gems/formatr/1.10.1/FormatR/Format), the [perlform docs](http://perldoc.perl.org/perlform.html), and in the provided [output example](examples/gyroutp).
|
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'banner_jobsub/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "banner_jobsub"
|
8
|
+
spec.version = BannerJobsub::VERSION
|
9
|
+
spec.authors = ["Ian Dillon"]
|
10
|
+
spec.email = ["dillon@etsu.edu"]
|
11
|
+
|
12
|
+
spec.summary = %q{"Write Ellucian Banner Jobsub jobs in Ruby."}
|
13
|
+
spec.homepage = "http://github.com/ian-d/banner_jobsub"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
17
|
+
spec.bindir = "exe"
|
18
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.required_ruby_version = '>= 2.1.0'
|
22
|
+
|
23
|
+
spec.add_runtime_dependency "ruby-oci8", ">= 2.1.5"
|
24
|
+
spec.add_runtime_dependency "formatr", ">= 1.10.1"
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
27
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
29
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "banner_jobsub"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/examples/gyrruby
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# First line _must_ be a shebang for your Ruby interpreter
|
3
|
+
|
4
|
+
require 'banner_jobsub'
|
5
|
+
include FormatR
|
6
|
+
|
7
|
+
# gyrruby is contrived example that prints some basic information on people
|
8
|
+
# who have birthdays between the start date and end date.
|
9
|
+
|
10
|
+
# BannerJobsub::Base has two required parameters:
|
11
|
+
# name: The job name as defined in Banner, must be upcase.
|
12
|
+
# params: An *Array* of parameter names to map to parameter values submitted
|
13
|
+
# with the job. The order of the names corresponds to the order of the
|
14
|
+
# parameter definition in Banner.
|
15
|
+
@ban_env = BannerJobsub::Base.new(name: 'GYRRUBY', params: [:start_date, :end_date])
|
16
|
+
|
17
|
+
# ruby-oci8 supports named parameter binding, but :1 and :2 would also work.
|
18
|
+
@sql = %Q[
|
19
|
+
select *
|
20
|
+
from spbpers
|
21
|
+
join spriden on spbpers_pidm = spriden_pidm
|
22
|
+
where spbpers_birth_date between :start_date and :end_date
|
23
|
+
and spriden_change_ind is null
|
24
|
+
order by spriden_last_name asc
|
25
|
+
]
|
26
|
+
|
27
|
+
# setup our print formatting for fixed output
|
28
|
+
top_format = @ban_env.header + <<-EOS
|
29
|
+
|
30
|
+
ID Name Birthday
|
31
|
+
========== ====================================== ==========
|
32
|
+
EOS
|
33
|
+
|
34
|
+
line_format = <<-EOS
|
35
|
+
@<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<
|
36
|
+
SPRIDEN_ID, FULL_NAME, SPBPERS_BIRTH_DATE
|
37
|
+
EOS
|
38
|
+
|
39
|
+
body_fmt = Format.new(top_format, line_format, @ban_env.footer)
|
40
|
+
body_fmt.setPageLength(@ban_env.page_length)
|
41
|
+
|
42
|
+
# The #conn attribute of @ban_env is the current database connection
|
43
|
+
# READ THE DOCS: http://www.rubydoc.info/gems/ruby-oci8/OCI8
|
44
|
+
cur = @ban_env.conn.parse(@sql)
|
45
|
+
|
46
|
+
# The #params attribute of @ban_env is a Hash with the params key used above
|
47
|
+
# which now have the value of the associated parameter passed from Banner
|
48
|
+
cur.bind_param(':start_date', @ban_env.params[:start_date])
|
49
|
+
cur.bind_param(':end_date', @ban_env.params[:end_date])
|
50
|
+
|
51
|
+
cur.exec
|
52
|
+
while (row = cur.fetch_hash) do
|
53
|
+
row['PAGE_NUMBER'] = body_fmt.pageNumber
|
54
|
+
row['FULL_NAME'] = "#{row['SPRIDEN_LAST_NAME']}, #{row['SPRIDEN_FIRST_NAME']}"
|
55
|
+
body_fmt.printFormatWithHash(row)
|
56
|
+
end
|
57
|
+
|
58
|
+
# The #log param is a file handle to your job's .log file (if running from INB)
|
59
|
+
@ban_env.log.puts "Found #{cur.row_count} people."
|
60
|
+
|
61
|
+
cur.close
|
62
|
+
|
63
|
+
body_fmt.finishPageWithoutFF(binding)
|
64
|
+
@ban_env.print_control_page
|
@@ -0,0 +1,60 @@
|
|
1
|
+
-- Delete reference in GJBJOBS
|
2
|
+
DELETE FROM GJBJOBS where GJBJOBS_NAME in ('GYRRUBY')
|
3
|
+
/
|
4
|
+
commit;
|
5
|
+
/
|
6
|
+
|
7
|
+
-- Insert Job into GJBJOBS
|
8
|
+
INSERT INTO GJBJOBS ( GJBJOBS_NAME, GJBJOBS_TITLE, GJBJOBS_ACTIVITY_DATE, GJBJOBS_SYSI_CODE,
|
9
|
+
GJBJOBS_JOB_TYPE_IND, GJBJOBS_DESC, GJBJOBS_COMMAND_NAME, GJBJOBS_PRNT_FORM, GJBJOBS_PRNT_CODE,
|
10
|
+
GJBJOBS_LINE_COUNT, GJBJOBS_VALIDATION ) VALUES ( 'GYRRUBY', 'BannerJobsub Ruby Example', sysdate,
|
11
|
+
'N', 'C', 'BannerJobsub Ruby Example', NULL, NULL, NULL, 55, NULL)
|
12
|
+
/
|
13
|
+
|
14
|
+
commit;
|
15
|
+
/
|
16
|
+
|
17
|
+
-- Insert of Parameter Definition to GJBPDEF
|
18
|
+
DELETE FROM GJBPDEF where GJBPDEF_JOB in ('GYRRUBY')
|
19
|
+
/
|
20
|
+
|
21
|
+
INSERT INTO GJBPDEF ( GJBPDEF_JOB, GJBPDEF_NUMBER, GJBPDEF_DESC, GJBPDEF_LENGTH, GJBPDEF_TYPE_IND,
|
22
|
+
GJBPDEF_OPTIONAL_IND, GJBPDEF_SINGLE_IND, GJBPDEF_ACTIVITY_DATE, GJBPDEF_LOW_RANGE,
|
23
|
+
GJBPDEF_HIGH_RANGE, GJBPDEF_HELP_TEXT, GJBPDEF_VALIDATION,
|
24
|
+
GJBPDEF_LIST_VALUES ) VALUES ( 'GYRRUBY', '01', 'Start Date:', 11, 'D', 'R', 'S', sysdate
|
25
|
+
, NULL, NULL, 'Enter Term Code. Click arrow for values.', NULL, 'STVTERM')
|
26
|
+
/
|
27
|
+
|
28
|
+
INSERT INTO GJBPDEF ( GJBPDEF_JOB, GJBPDEF_NUMBER, GJBPDEF_DESC, GJBPDEF_LENGTH, GJBPDEF_TYPE_IND,
|
29
|
+
GJBPDEF_OPTIONAL_IND, GJBPDEF_SINGLE_IND, GJBPDEF_ACTIVITY_DATE, GJBPDEF_LOW_RANGE,
|
30
|
+
GJBPDEF_HIGH_RANGE, GJBPDEF_HELP_TEXT, GJBPDEF_VALIDATION,
|
31
|
+
GJBPDEF_LIST_VALUES ) VALUES ( 'GYRRUBY', '02', 'End Date:', 11, 'D', 'R', 'S', sysdate
|
32
|
+
, NULL, NULL, 'Level: [UG/GR/%]', NULL, NULL)
|
33
|
+
/
|
34
|
+
|
35
|
+
commit;
|
36
|
+
/
|
37
|
+
|
38
|
+
-- Insert Default parameter in GJBPDFT
|
39
|
+
DELETE FROM GJBPDFT where GJBPDFT_JOB in ('GYRRUBY')
|
40
|
+
/
|
41
|
+
|
42
|
+
INSERT INTO GJBPDFT ( GJBPDFT_JOB, GJBPDFT_NUMBER, GJBPDFT_ACTIVITY_DATE, GJBPDFT_USER_ID,
|
43
|
+
GJBPDFT_VALUE, GJBPDFT_JPRM_CODE ) VALUES ('GYRRUBY', '01', sysdate, NULL, '23-JUN-1980', NULL)
|
44
|
+
/
|
45
|
+
INSERT INTO GJBPDFT ( GJBPDFT_JOB, GJBPDFT_NUMBER, GJBPDFT_ACTIVITY_DATE, GJBPDFT_USER_ID,
|
46
|
+
GJBPDFT_VALUE, GJBPDFT_JPRM_CODE ) VALUES ('GYRRUBY', '02', sysdate, NULL, '23-JUN-1980', NULL)
|
47
|
+
/
|
48
|
+
|
49
|
+
commit;
|
50
|
+
/
|
51
|
+
|
52
|
+
-- Insert of reference in GUBOBJS
|
53
|
+
DELETE FROM GUBOBJS WHERE GUBOBJS_NAME = 'GYRRUBY';
|
54
|
+
|
55
|
+
INSERT INTO GUBOBJS (GUBOBJS_NAME, GUBOBJS_DESC, GUBOBJS_OBJT_CODE, GUBOBJS_SYSI_CODE,GUBOBJS_USER_ID,
|
56
|
+
GUBOBJS_ACTIVITY_DATE, GUBOBJS_HELP_IND, GUBOBJS_EXTRACT_ENABLED_IND)
|
57
|
+
VALUES ('GYRRUBY', 'BannerJobsub Ruby Example','JOBS', 'G', 'LOCAL', SYSDATE, 'N', 'N');
|
58
|
+
|
59
|
+
commit;
|
60
|
+
/
|
data/examples/gyrschd
ADDED
@@ -0,0 +1,108 @@
|
|
1
|
+
#! /usr/bin/env ruby
|
2
|
+
# First line _must_ be a shebang for your Ruby interpreter
|
3
|
+
|
4
|
+
require 'banner_jobsub'
|
5
|
+
require 'net/smtp'
|
6
|
+
require 'erb'
|
7
|
+
require 'ostruct'
|
8
|
+
|
9
|
+
# gyrschd is a bit more complicated example that finds all the primary instructors
|
10
|
+
# for a given term, then emails them their assigned sections from an ERB template.
|
11
|
+
# Some comments are removed from code already introduced in gyrruby
|
12
|
+
# be careful running this in a real environment
|
13
|
+
|
14
|
+
# This is a terrible way to send email, btw. Use something like Pony for real use.
|
15
|
+
# Or if you're going to send a _lot_ of email, an asynchornous worker system
|
16
|
+
# like resque
|
17
|
+
def send_email(to:, body:, opts: {})
|
18
|
+
opts[:server] ||= 'smtp.myschool.edu'
|
19
|
+
opts[:from] ||= 'banner@myschool.edu'
|
20
|
+
opts[:from_alias] ||= 'Banner Jobsub'
|
21
|
+
opts[:subject] ||= "Section List"
|
22
|
+
opts[:body] ||= body
|
23
|
+
|
24
|
+
msg = <<END_OF_MESSAGE
|
25
|
+
From: #{opts[:from_alias]} <#{opts[:from]}>
|
26
|
+
To: <#{to}>
|
27
|
+
Subject: #{opts[:subject]}
|
28
|
+
|
29
|
+
#{opts[:body]}
|
30
|
+
END_OF_MESSAGE
|
31
|
+
|
32
|
+
Net::SMTP.start(opts[:server]) do |smtp|
|
33
|
+
smtp.send_message msg, opts[:from], to
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@ban_env = BannerJobsub::Base.new(name: 'GYRSCHD', params: [:term_code])
|
38
|
+
|
39
|
+
# a common pattern here is to move long strings (like SQL) into DATA (everything past __END__)
|
40
|
+
# then evaluate it at run-time to bring it into scope. this keeps the actual logic
|
41
|
+
# of the program a lot more readable.
|
42
|
+
eval DATA.read
|
43
|
+
|
44
|
+
# instead of running one large query and managing our control flow row by result row,
|
45
|
+
# we're going to do two simpler queries and build a simple data structure
|
46
|
+
|
47
|
+
@instructors = {} # A hash to hold the instructors, key will be pidm
|
48
|
+
cur = @ban_env.conn.parse(@sql_get_instructors)
|
49
|
+
cur.exec(@ban_env.params[:term_code])
|
50
|
+
while (row = cur.fetch_hash) do
|
51
|
+
r = row.each_with_object({}) { |(k, v), m| m[k.downcase.to_sym] = v } #convert upcase column name to symbols
|
52
|
+
@instructors[r[:pidm]] = r
|
53
|
+
@instructors[r[:pidm]]['sections'] = []
|
54
|
+
end
|
55
|
+
cur.close
|
56
|
+
|
57
|
+
# now find all the sections and push into the instructor's sections Array
|
58
|
+
cur = @ban_env.conn.parse(@sql_get_sections)
|
59
|
+
cur.exec(@ban_env.params[:term_code])
|
60
|
+
while (row = cur.fetch_hash) do
|
61
|
+
r = row.each_with_object({}) { |(k, v), m| m[k.downcase.to_sym] = v }
|
62
|
+
@instructors[r[:pidm]]['sections'] << r
|
63
|
+
end
|
64
|
+
cur.close
|
65
|
+
|
66
|
+
# We're going to assume our template is in the DATA_HOME
|
67
|
+
@template = ERB.new(File.read("#{ENV['DATA_HOME']}/gyrschd.erb"), nil, '-')
|
68
|
+
@instructors.each do |pidm, record|
|
69
|
+
temp_s = OpenStruct.new(record)
|
70
|
+
body = @template.result(temp_s.instance_eval {binding})
|
71
|
+
|
72
|
+
# Uncomment the following line w/ caution
|
73
|
+
#send_email(to: temp_s.email_address, body: body)
|
74
|
+
|
75
|
+
# DEBUG
|
76
|
+
@ban_env.log.puts "Would have sent this to #{temp_s.email_address}:\n #{body}\n"
|
77
|
+
end
|
78
|
+
|
79
|
+
__END__
|
80
|
+
@sql_get_instructors = <<-SQL_END
|
81
|
+
select distinct spriden_pidm pidm,
|
82
|
+
spriden_id id,
|
83
|
+
spriden_last_name last_name,
|
84
|
+
spriden_first_name first_name,
|
85
|
+
goremal_email_address email_address,
|
86
|
+
sirasgn_term_code term_code
|
87
|
+
from sirasgn
|
88
|
+
join spriden on sirasgn_pidm = spriden_pidm
|
89
|
+
join goremal on spriden_pidm = goremal_pidm
|
90
|
+
where sirasgn_term_code = :1
|
91
|
+
and goremal_emal_code = 'CAMP'
|
92
|
+
and goremal_status_ind = 'A'
|
93
|
+
and spriden_change_ind is null
|
94
|
+
order by spriden_pidm
|
95
|
+
SQL_END
|
96
|
+
|
97
|
+
@sql_get_sections = <<-SQL_END
|
98
|
+
select sirasgn_pidm pidm, ssbsect_subj_code subj_code, ssbsect_crse_numb crse_numb, ssbsect_crn crn, scbcrse_title title
|
99
|
+
from ssbsect
|
100
|
+
join scbcrse on scbcrse_subj_code = ssbsect_subj_code and scbcrse_crse_numb = ssbsect_crse_numb
|
101
|
+
join sirasgn on ssbsect_term_code = sirasgn_term_code and ssbsect_crn = sirasgn_crn
|
102
|
+
where ssbsect_term_code = :1
|
103
|
+
and scbcrse_eff_term = (select max(scbcrse_eff_term)
|
104
|
+
from scbcrse i
|
105
|
+
where i.scbcrse_subj_code = ssbsect_subj_code
|
106
|
+
and i.scbcrse_crse_numb = ssbsect_crse_numb)
|
107
|
+
order by ssbsect_subj_code asc, ssbsect_crse_numb asc
|
108
|
+
SQL_END
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= first_name %> <%= last_name %>,
|
2
|
+
Below is the list of sections for which you are the primary instructor for term <%= term_code %>.
|
3
|
+
|
4
|
+
<% for section in sections -%>
|
5
|
+
<%= section[:subj_code] %>-<%= section[:crse_numb] %>-<%= section[:crn] %> : <%= section[:title] %>
|
6
|
+
<% end -%>
|
7
|
+
|
8
|
+
Good luck!
|
@@ -0,0 +1,50 @@
|
|
1
|
+
-- Delete reference in GJBJOBS
|
2
|
+
DELETE FROM GJBJOBS where GJBJOBS_NAME in ('GYRSCHD')
|
3
|
+
/
|
4
|
+
commit;
|
5
|
+
/
|
6
|
+
|
7
|
+
-- Insert Job into GJBJOBS
|
8
|
+
INSERT INTO GJBJOBS ( GJBJOBS_NAME, GJBJOBS_TITLE, GJBJOBS_ACTIVITY_DATE, GJBJOBS_SYSI_CODE,
|
9
|
+
GJBJOBS_JOB_TYPE_IND, GJBJOBS_DESC, GJBJOBS_COMMAND_NAME, GJBJOBS_PRNT_FORM, GJBJOBS_PRNT_CODE,
|
10
|
+
GJBJOBS_LINE_COUNT, GJBJOBS_VALIDATION ) VALUES ( 'GYRSCHD', 'BannerJobsub Ruby Example', sysdate,
|
11
|
+
'N', 'C', 'BannerJobsub Ruby Example', NULL, NULL, NULL, 55, NULL)
|
12
|
+
/
|
13
|
+
|
14
|
+
commit;
|
15
|
+
/
|
16
|
+
|
17
|
+
-- Insert of Parameter Definition to GJBPDEF
|
18
|
+
DELETE FROM GJBPDEF where GJBPDEF_JOB in ('GYRSCHD')
|
19
|
+
/
|
20
|
+
|
21
|
+
INSERT INTO GJBPDEF ( GJBPDEF_JOB, GJBPDEF_NUMBER, GJBPDEF_DESC, GJBPDEF_LENGTH, GJBPDEF_TYPE_IND,
|
22
|
+
GJBPDEF_OPTIONAL_IND, GJBPDEF_SINGLE_IND, GJBPDEF_ACTIVITY_DATE, GJBPDEF_LOW_RANGE,
|
23
|
+
GJBPDEF_HIGH_RANGE, GJBPDEF_HELP_TEXT, GJBPDEF_VALIDATION,
|
24
|
+
GJBPDEF_LIST_VALUES ) VALUES ( 'GYRSCHD', '01', 'Term Code:', 8, 'C', 'R', 'S', sysdate
|
25
|
+
, NULL, NULL, 'Enter Term Code. Click arrow for values.', NULL, 'STVTERM')
|
26
|
+
/
|
27
|
+
|
28
|
+
commit;
|
29
|
+
/
|
30
|
+
|
31
|
+
-- Insert Default parameter in GJBPDFT
|
32
|
+
DELETE FROM GJBPDFT where GJBPDFT_JOB in ('GYRSCHD')
|
33
|
+
/
|
34
|
+
|
35
|
+
INSERT INTO GJBPDFT ( GJBPDFT_JOB, GJBPDFT_NUMBER, GJBPDFT_ACTIVITY_DATE, GJBPDFT_USER_ID,
|
36
|
+
GJBPDFT_VALUE, GJBPDFT_JPRM_CODE ) VALUES ('GYRSCHD', '01', sysdate, NULL, '201610', NULL)
|
37
|
+
/
|
38
|
+
|
39
|
+
commit;
|
40
|
+
/
|
41
|
+
|
42
|
+
-- Insert of reference in GUBOBJS
|
43
|
+
DELETE FROM GUBOBJS WHERE GUBOBJS_NAME = 'GYRSCHD';
|
44
|
+
|
45
|
+
INSERT INTO GUBOBJS (GUBOBJS_NAME, GUBOBJS_DESC, GUBOBJS_OBJT_CODE, GUBOBJS_SYSI_CODE,GUBOBJS_USER_ID,
|
46
|
+
GUBOBJS_ACTIVITY_DATE, GUBOBJS_HELP_IND, GUBOBJS_EXTRACT_ENABLED_IND)
|
47
|
+
VALUES ('GYRSCHD', 'BannerJobsub Ruby Example','JOBS', 'G', 'LOCAL', SYSDATE, 'N', 'N');
|
48
|
+
|
49
|
+
commit;
|
50
|
+
/
|
@@ -0,0 +1,176 @@
|
|
1
|
+
# rubocop:disable Metrics/LineLength
|
2
|
+
require 'formatr'
|
3
|
+
require 'oci8'
|
4
|
+
require 'yaml'
|
5
|
+
require 'banner_jobsub/version'
|
6
|
+
|
7
|
+
module BannerJobsub
|
8
|
+
class Base
|
9
|
+
attr_reader :name, :title, :params, :conn, :header, :footer, :log, :page_length
|
10
|
+
|
11
|
+
def initialize(name:, params:, opts: {})
|
12
|
+
@name = name
|
13
|
+
@config = {
|
14
|
+
username: ENV['BANUID'],
|
15
|
+
password: ENV['PSWD'],
|
16
|
+
instance: ENV['ORACLE_SID'],
|
17
|
+
seed_one: nil,
|
18
|
+
seed_three: nil,
|
19
|
+
page_length: 55,
|
20
|
+
footer: '\f',
|
21
|
+
header: ''
|
22
|
+
}
|
23
|
+
|
24
|
+
configure_from_files
|
25
|
+
configure_from_hash(opts)
|
26
|
+
@config.each { |k, v| fail "Required configuration parameter \"#{k}\" is null." if v.nil? }
|
27
|
+
|
28
|
+
set_db_connection
|
29
|
+
set_role_security
|
30
|
+
|
31
|
+
@title = @conn.select_one('SELECT GJBJOBS_TITLE FROM GJBJOBS WHERE GJBJOBS_NAME = :1', @name)[0]
|
32
|
+
|
33
|
+
get_parameters(params)
|
34
|
+
@page_length = @config[:page_length].to_i if @page_length.nil?
|
35
|
+
|
36
|
+
set_header
|
37
|
+
set_footer
|
38
|
+
|
39
|
+
# Manage STDOUT/LOG
|
40
|
+
@log = $stdout
|
41
|
+
$stdout = File.new(ARGV[2], 'w') if ARGV[2]
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_header(page_number = 1)
|
45
|
+
temp_fmt = FormatR::Format.new(@header, '')
|
46
|
+
temp_fmt.printFormatWithHash('PAGE_NUMBER' => page_number)
|
47
|
+
end
|
48
|
+
|
49
|
+
def print_control_page(page_number = '')
|
50
|
+
control_format = "Paramater Name Parameter Value\n"
|
51
|
+
control_format += '------------------------ ---------------'
|
52
|
+
line_format = "@<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<\n"
|
53
|
+
line_format += 'PARAM_NAME, PARAM_VALUE'
|
54
|
+
temp_fmt = FormatR::Format.new(@header + control_format, line_format)
|
55
|
+
@params.each do |k, v|
|
56
|
+
h = { 'PARAM_NAME' => k, 'PARAM_VALUE' => v, 'PAGE_NUMBER' => page_number }
|
57
|
+
temp_fmt.printFormatWithHash(h)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
private def get_parameters(params)
|
62
|
+
@params = {}
|
63
|
+
params_def = []
|
64
|
+
cur = @conn.exec('SELECT * FROM GJBPDEF WHERE GJBPDEF_JOB = :1 ORDER BY GJBPDEF_NUMBER', @name)
|
65
|
+
while (r = cur.fetch_hash)
|
66
|
+
p_def = r.each_with_object({}) { |(k, v), m| m[k.downcase.to_sym] = v }
|
67
|
+
p = params[p_def[:gjbpdef_number].to_i - 1]
|
68
|
+
@params[p] = p_def[:gjbpdef_single_ind] == 'S' ? nil : []
|
69
|
+
params_def << p_def
|
70
|
+
end
|
71
|
+
cur.close
|
72
|
+
|
73
|
+
if ENV['ONE_UP']
|
74
|
+
get_parameter_values_from_db(params, params_def)
|
75
|
+
elsif File.exist?("#{@name.downcase}.yaml")
|
76
|
+
get_parameter_values_from_file
|
77
|
+
else
|
78
|
+
get_parameter_values_from_prompt(params, params_def)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
private def get_parameter_values_from_file
|
83
|
+
YAML.load(IO.read("#{@name.downcase}.yaml")).each { |k, v| @params[k.to_sym] = v }
|
84
|
+
end
|
85
|
+
|
86
|
+
private def get_parameter_values_from_db(params, params_def)
|
87
|
+
cur = @conn.exec('SELECT * FROM GJBPRUN WHERE GJBPRUN_JOB = :1 AND GJBPRUN_ONE_UP_NO = :2 ORDER BY GJBPRUN_NUMBER', @name, ENV['ONE_UP'])
|
88
|
+
while (r = cur.fetch_hash)
|
89
|
+
p_num = r['GJBPRUN_NUMBER'].to_i
|
90
|
+
if p_num == 99
|
91
|
+
@page_length = r['GJBPRUN_VALUE'].to_i
|
92
|
+
next
|
93
|
+
end
|
94
|
+
if p_num > params.count then fail "FATAL: GJBPRUN parameter number #{p_num} greater than passed parameter list." end
|
95
|
+
p = params[p_num - 1]
|
96
|
+
if params_def[p_num - 1][:gjbpdef_single_ind] == 'S'
|
97
|
+
@params[p] = r['GJBPRUN_VALUE']
|
98
|
+
else
|
99
|
+
@params[p] << r['GJBPRUN_VALUE']
|
100
|
+
end
|
101
|
+
end
|
102
|
+
if cur.row_count == 0 then fail "FATAL: Unable to validate one up ##{ENV['ONE_UP']} with job #{@name}." end
|
103
|
+
cur.close
|
104
|
+
|
105
|
+
@conn.exec('DELETE FROM GJBPRUN WHERE GJBPRUN_JOB = :1 AND GJBPRUN_ONE_UP_NO = :2', @name, ENV['ONE_UP'])
|
106
|
+
end
|
107
|
+
|
108
|
+
private def get_parameter_values_from_prompt(params, params_def)
|
109
|
+
params.each_index do |i|
|
110
|
+
p = params[i]
|
111
|
+
@params[p] = (print "Value for #{p}: "; gets.chomp)
|
112
|
+
@params[p] = @params[p].split(',') if params_def[i][:gjbpdef_single_ind] == 'M'
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
private def configure_from_hash(opts)
|
117
|
+
opts.each { |k, v| @config[k.to_sym] = v if @config.keys.include?(k.to_sym) }
|
118
|
+
end
|
119
|
+
|
120
|
+
private def configure_from_files
|
121
|
+
files = ["#{ENV['BANNER_HOME']}/admin/banner_jobsub.yaml", "#{Dir.home}/.banner_jobsub"]
|
122
|
+
files.each do |f|
|
123
|
+
begin
|
124
|
+
config = YAML.load(IO.read(f))
|
125
|
+
config.each { |k, v| @config[k.to_sym] = v if @config.keys.include?(k.to_sym) }
|
126
|
+
rescue Errno::ENOENT # Ignore missing file exceptions.
|
127
|
+
rescue Psych::SyntaxError => e
|
128
|
+
raise "Error parsing YAML in #{f}: #{e}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
private def set_db_connection
|
134
|
+
@conn = OCI8.new(@config[:username], @config[:password], @config[:instance])
|
135
|
+
end
|
136
|
+
|
137
|
+
private def set_role_security
|
138
|
+
password = ''
|
139
|
+
|
140
|
+
cursor = @conn.parse('begin bansecr.g$_security_pkg.g$_verify_password1_prd(:p_object,:p_version,:p_password, :p_role); end;')
|
141
|
+
cursor.exec @name, [nil, String], [nil, String], [nil, String]
|
142
|
+
|
143
|
+
return if cursor[3] == 'INSECURED'
|
144
|
+
|
145
|
+
@conn.exec('begin :p_result := G$_SECURITY.G$_DECRYPT_FNC( :p_password, :p_seed ); end;', ['', String, 255], [cursor[3], String, 255], [@config[:seed_three], Fixnum]) { |*outvars| password = outvars[0] }
|
146
|
+
|
147
|
+
cursor = @conn.parse('begin bansecr.g$_security_pkg.g$_verify_password1_prd(:p_object,:p_version,:p_password, :p_role); end;')
|
148
|
+
cursor.exec @name, [nil, String], [password, String], [nil, String]
|
149
|
+
|
150
|
+
@conn.exec('begin :p_result := G$_SECURITY.G$_DECRYPT_FNC( :p_password, :p_seed ); end;', ['', String, 255], [cursor[3], String, 255], [@config[:seed_one], Fixnum]) { |*outvars| password = outvars[0] }
|
151
|
+
|
152
|
+
@conn.exec("begin DBMS_SESSION.SET_ROLE('#{cursor[4]} IDENTIFIED BY \"#{password}\"'); end;")
|
153
|
+
end
|
154
|
+
|
155
|
+
private def set_footer
|
156
|
+
@footer = @config[:footer]
|
157
|
+
end
|
158
|
+
|
159
|
+
private def set_header
|
160
|
+
if !@config[:header].empty?
|
161
|
+
@header = @config[:header]
|
162
|
+
else
|
163
|
+
inst = get_institution_name
|
164
|
+
@header = <<EOH
|
165
|
+
#{Time.now.strftime('%d-%b-%Y %I:%M %p').upcase} #{inst.center(110)} PAGE: @<<<
|
166
|
+
PAGE_NUMBER
|
167
|
+
#{@name} #{@title.center(132)}
|
168
|
+
EOH
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
private def get_institution_name
|
173
|
+
@conn.select_one('SELECT GUBINST_NAME FROM GUBINST WHERE GUBINST_KEY = \'INST\'')[0]
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: banner_jobsub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ian Dillon
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: ruby-oci8
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.1.5
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.1.5
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: formatr
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 1.10.1
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 1.10.1
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.11'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.11'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '10.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '10.0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '3.0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '3.0'
|
83
|
+
description:
|
84
|
+
email:
|
85
|
+
- dillon@etsu.edu
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- ".gitignore"
|
91
|
+
- ".rspec"
|
92
|
+
- ".rubocop.yml"
|
93
|
+
- ".travis.yml"
|
94
|
+
- Gemfile
|
95
|
+
- LICENSE.txt
|
96
|
+
- README.md
|
97
|
+
- Rakefile
|
98
|
+
- banner_jobsub.gemspec
|
99
|
+
- bin/console
|
100
|
+
- bin/setup
|
101
|
+
- examples/gyrruby
|
102
|
+
- examples/gyrruby.yaml
|
103
|
+
- examples/gyrruby_install.sql
|
104
|
+
- examples/gyrschd
|
105
|
+
- examples/gyrschd.erb
|
106
|
+
- examples/gyrschd_install.sql
|
107
|
+
- lib/banner_jobsub.rb
|
108
|
+
- lib/banner_jobsub/version.rb
|
109
|
+
homepage: http://github.com/ian-d/banner_jobsub
|
110
|
+
licenses:
|
111
|
+
- MIT
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: 2.1.0
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - ">="
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.4.8
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: '"Write Ellucian Banner Jobsub jobs in Ruby."'
|
133
|
+
test_files: []
|