banner_jobsub 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.rubocop.yml ADDED
@@ -0,0 +1,2 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.1
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.11.2
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in banner_jobsub.gemspec
4
+ gemspec
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,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -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
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
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,2 @@
1
+ start_date: 23-JUN-1980
2
+ end_date: 24-JUN-1980
@@ -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
@@ -0,0 +1,3 @@
1
+ module BannerJobsub
2
+ VERSION = '0.1.0'
3
+ 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: []