smartnotify2 0.4.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
+ SHA256:
3
+ metadata.gz: e687c007b40ebd3e8771c1fb9cf437bdfad4987d92c427d2bdc093d195ee10d1
4
+ data.tar.gz: eefb144a2d6eaf3a065ac8139dea554221541670a26348e9cde5ef6421e4c12a
5
+ SHA512:
6
+ metadata.gz: 9c37becbabaf10e56fd0d526685faaeec249c90c9bcbcfc0c10d4bba4ab0501ea6b40d9cc465479c20f1ca966a2062b1a9346655f9bae85b58e32629687f4a12
7
+ data.tar.gz: c60957633ede9af4f60ce2c43db426c6c88ebe2477eb012661d0ddce476fd1b30eba07a07a163a9d7196a10ef28f345dfef3fdba54dd8e64f3113e1cb3e07bdf
data/README.md ADDED
@@ -0,0 +1,54 @@
1
+ # SmartNotify
2
+
3
+ Ruby Gem designed for sending various types of notifications via a common configurable interface.
4
+
5
+ ## Overview
6
+ The gem makes use of two components, modules, and templates.
7
+
8
+ Modules are defined within this gem, and provide various forms of generic notification functionality. The modules are created to be reusable. A module could be responsible for sending emails, posting Slack notifications, making a REST call to an external API, whatever.
9
+
10
+ Templates on the other hand, consume a specific module, in conjunction with template specific configuration, creating very specific use cases. These use cases could be team specific, allowing different consumers to tweak who, and how notifications are distributed.
11
+
12
+ ## Why
13
+ There was a need to easily send SLA incident emails to the correct person on support, as well as to a MS Teams channel. A module was created `rotation_emailer` which could send emails, based on a given email template, and support rotation csv file. With that in place, a template was created `incident_start_email` which defines where the specific email template, and support rotation csv file is located for this particular instance. This is awesome, because a new team or solution could create a template, changing only the support rotation csv location, and get the same functionality for next to no setup cost.
14
+
15
+
16
+ ## Usage
17
+ Add smartnotify to your Gemfile, pointing at GitHub.
18
+ ```
19
+ gem 'smartnotify', git: 'https://github.cerner.com/PHPerfImp/smartnotify.git', branch: 'master'
20
+ ```
21
+
22
+ Within your code add:
23
+ ```ruby
24
+ require 'smartnotify'
25
+ # ... your logic ...
26
+ smartnotify = SmartNotify.new
27
+ smartnotify.run(template, json, [debug], [dryrun])
28
+ ```
29
+
30
+ *Note: when updates are made to the gem in github, bundle update & bundle install must be run to pull in the changes.
31
+
32
+ | Param | Type | Requirement | Default | Description |
33
+ | ---- | ---- | ----------- | ------- | --------------- |
34
+ | template | String | Required | | The id of the template to use. The templates are configured externally in [PHPerfImp/smartnotify-config](https://github.cerner.com/PHPerfImp/smartnotify-config) |
35
+ | json | String | Required | | The JSON key/value pairs to be used as input to the selected template. Each template defines what keys must be provided. |
36
+ | environment | String | Optional | production | The id of the environment configuration to use. Choices are local, development, staging, and production. |
37
+ | debug | Boolean | Optional | false | Enables debug logging within SmartNotify. |
38
+ | dryrun | Boolean | Optional | false | Enables debug logging within SmartNotify, and disables sending any notifications for testing purposes. |
39
+
40
+ ### Example
41
+ ```ruby
42
+ smartnotify = SmartNotify.new
43
+ smartnotify.run('incident_start_email', "{\"mnemonic\": \"sbmcin\", \"cerner_mnemonic\": \"UNVR_NY\", \"link\": \"https://jira2.cerner.com/browse/PERFIMPDEV-1349\", \"title\": \"Readmission SLA Exceeded\", \"message\": \"Readmission SLA exceeded, please check the JIRA for more information.\"}", 'production')
44
+ ```
45
+
46
+ ## Modules
47
+ The following are the currently available modules that can be consumed. Follow the link to get more information on
48
+ intended usage, and configuration.
49
+
50
+ * [Rotation Emailer](modules/roatation_emailer/README.md)
51
+
52
+ ## Releasing New Version
53
+
54
+ *N/A - As long as we are using our internal GitHub for storage of the gem, there is no need to 'release' a new version. Using a different version of the branch can be achieved by pointing the Gemfile reference at a different ref. See http://bundler.io/v1.12/git.html for more information.
@@ -0,0 +1 @@
1
+ external-config-path: 'https://raw.github.cerner.com/PHPerfImp/smartnotify-config/master/config/config.yml'
@@ -0,0 +1,31 @@
1
+ # Module - Rotation Emailer
2
+
3
+ **Module ID:** `rotation_emailer`
4
+
5
+ ## Required Configuration
6
+
7
+ * *email_template* - A URL pointed to the template of the email message to send. This document should be a .erb file.
8
+ The data is fed into the template from the provided json, as a hash. *e.g accessing a title key would look like
9
+ `<%= data['title'] %>`*
10
+
11
+ * *support_rotation* - A URL pointed to a CSV file containing email addresses, combined with start/end times for
12
+ when the given address is valid to email. On each run, the file will be parsed looking for emails that are valid at that
13
+ time and will send the message to all the addresses as one group email. At a minimum, the following three columns
14
+ with headers must be specified:
15
+
16
+ * `Start Time` - Formatted as 12/Aug/2017. This is the date, starting at the beginning of the day, that the email
17
+ address can start being emailed.
18
+ * `End Time` - Formatted as 18/Aug/2017. This is the date, ending at midnight, that the email address is no longer
19
+ valid to notify after.
20
+ * `Email Address` - Email address to notify.
21
+
22
+ *Note:*
23
+ * *All times a calculated with the configured timezone of Central Time (US & Canada)*
24
+ * *Column headers are case sensitive.*
25
+
26
+ ## Required JSON keys
27
+ While most of the JSON key/value pairs are defined based on what
28
+ the template needs, this module requires that a `title` JSON key
29
+ be provided which is used as the subject of the email. If no title
30
+ key is defined, a fallback *'Rotation Emailer Notification'* title
31
+ will be used as the email subject instead.
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mail'
4
+ require 'yaml'
5
+ require 'csv'
6
+ require 'open-uri'
7
+ require 'logging'
8
+
9
+ class NotificationModule
10
+
11
+ def initialize(config)
12
+ @config = config
13
+ @log = Logging.logger['rotation_emailer']
14
+ end
15
+
16
+ def run
17
+
18
+ c = @config
19
+
20
+ @log.info ''
21
+ @log.info 'Starting rotation_emailer.rb logic...'
22
+
23
+ # Setup Mailer
24
+ @log.info ''
25
+ @log.info 'Setting up Mail.defaults with the following configuration:'
26
+ @log.info " host: #{c[:global]['smtp_host']}"
27
+ @log.info " port: #{c[:global]['smtp_port']}"
28
+
29
+
30
+ Mail.defaults do
31
+ delivery_method :smtp, {
32
+ :address => c[:global]['smtp_host'],
33
+ :port => c[:global]['smtp_port']
34
+ }
35
+ end
36
+
37
+ # Load Email Addresses
38
+
39
+ send_list = c[:config]['always_email']
40
+
41
+ unless c[:config]['support_rotation'].nil?
42
+ @log.info ''
43
+ @log.info 'Loading support rotation from:'
44
+ @log.info " #{c[:config]['support_rotation']}"
45
+ CSV.new(open(c[:config]['support_rotation']), :headers => :first_row).each do |email|
46
+ send_list.push("#{email['Email Address']}") if active_email(email, c[:global]['timezone'])
47
+ end
48
+ end
49
+
50
+ send_list.uniq!
51
+
52
+ if send_list.empty?
53
+ @log.error 'No email addresses are setup for the current time.'
54
+ return false
55
+ end
56
+
57
+ @log.info ''
58
+ @log.info 'Found the following email addresses to notify:'
59
+
60
+ send_list.each do |recipient|
61
+ @log.info " #{recipient}"
62
+ end
63
+
64
+ # Load Template
65
+ @log.info ''
66
+ @log.info 'Loading email template from:'
67
+ @log.info " #{c[:config]['email_template']}"
68
+
69
+ email_template = open(c[:config]['email_template']).read
70
+
71
+ # Populate Template
72
+ b = binding
73
+ b.local_variable_set(:data, c[:data])
74
+ message = ERB.new(email_template).result(b)
75
+
76
+ if c[:global]['dryrun']
77
+ @log.info ''
78
+ @log.info 'Not sending email because dryrun is enabled.'
79
+ @log.info 'Would have emailed the following message:'
80
+ @log.info ''
81
+ @log.info "SUBJECT: #{c[:data]['title']}"
82
+ @log.info ''
83
+ @log.info '--- MESSAGE START ---'
84
+ message.each_line do |line|
85
+ @log.info " #{line.chomp}"
86
+ end
87
+ @log.info '--- MESSAGE END ---'
88
+ else
89
+ # Send The Emails
90
+ @log.info ''
91
+ @log.info 'Sending Emails...'
92
+
93
+ title = c[:data]['title'].nil? ? 'Rotation Emailer Notification' : c[:data]['title']
94
+ send_email(title, c[:global]['smtp_from'], send_list, message)
95
+ end
96
+ @log.info ''
97
+ @log.info ' Finished rotation_emailer.rb logic.'
98
+ end
99
+
100
+ private
101
+
102
+ def active_email(email, tz)
103
+ start_time = DateTime.parse(email['Start Time'] + ' ' + tz)
104
+ end_time = DateTime.parse(email['End Time'] + ' ' + tz) + 1
105
+ current_time = DateTime.now
106
+ start_time <= current_time and end_time > current_time
107
+ end
108
+
109
+ def send_email(subject_text, from_email, to_email, body_text)
110
+ Mail.deliver do
111
+ to to_email
112
+ from from_email
113
+ subject subject_text
114
+ html_part do
115
+ content_type 'text/html; charset=UTF-8'
116
+ body body_text
117
+ end
118
+ end
119
+ end
120
+ end
File without changes
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'mail'
4
+ require 'yaml'
5
+ require 'csv'
6
+ require 'open-uri'
7
+ require 'logging'
8
+ require 'slack-notifier'
9
+
10
+ class NotificationModule
11
+
12
+ def initialize(config)
13
+ @config = config
14
+ @log = Logging.logger['slack_notifier']
15
+ end
16
+
17
+ def run
18
+
19
+ c = @config
20
+
21
+ @log.info ''
22
+ @log.info 'Starting slack_notifier.rb logic...'
23
+
24
+ # Load Template
25
+ @log.info ''
26
+ @log.info 'Loading message template from:'
27
+ @log.info " #{c[:config]['message_template']}"
28
+
29
+ message_template = open(c[:config]['message_template']).read
30
+
31
+ # Populate Template
32
+ b = binding
33
+ b.local_variable_set(:data, c[:data])
34
+ message = ERB.new(message_template).result(b)
35
+
36
+ if c[:global]['dryrun']
37
+ @log.info ''
38
+ @log.info 'Not sending slack message because dryrun is enabled.'
39
+ @log.info 'Would have posted the following message:'
40
+ @log.info ''
41
+ @log.info '--- MESSAGE START ---'
42
+ message.each_line do |line|
43
+ @log.info " #{line.chomp}"
44
+ end
45
+ @log.info '--- MESSAGE END ---'
46
+ else
47
+ # Send The Emails
48
+ @log.info ''
49
+ @log.info 'Posting Message to Slack...'
50
+ @log.info " Channel: #{c[:config]['channel']} "
51
+ @log.info " Username: #{c[:config]['username']} "
52
+
53
+ notifier = Slack::Notifier.new "#{c[:config]['webhook']}" do
54
+ defaults channel: "#{c[:config]['channel']}",
55
+ username: "#{c[:config]['username']}"
56
+ end
57
+ notifier.ping message
58
+ end
59
+ @log.info ''
60
+ @log.info ' Finished slack_notifier.rb logic.'
61
+ end
62
+ end
@@ -0,0 +1,99 @@
1
+ require 'yaml'
2
+ require 'erb'
3
+ require 'json'
4
+ require 'open-uri'
5
+ require 'logging'
6
+
7
+ class SmartNotify
8
+ attr_accessor :config
9
+
10
+ def initialize
11
+ Logging.logger.root.appenders = Logging.appenders.stdout
12
+ Logging.logger.root.level = :debug
13
+ @log = Logging.logger['smartnotify']
14
+ end
15
+
16
+ def run(template, json, env = 'production', debug = false, dryrun = false)
17
+
18
+ # Ensure Options Provided
19
+ if json.nil? || template.nil? || env.nil?
20
+ @log.error 'Must provide template, JSON data, and environment name.'
21
+ return false
22
+ end
23
+
24
+ # Load Configuration
25
+ internal_config = YAML.load_file(File.join(__dir__, 'config/config.yml'))
26
+ @log.info 'Loading SmartNotify config from:'
27
+ @log.info " #{internal_config['external-config-path']}"
28
+
29
+ external_config = nil
30
+ begin
31
+ external_config = YAML.load(open(internal_config['external-config-path']).read)
32
+ rescue
33
+ @log.error 'Unable to load and parse configuration.'
34
+ @log.error 'Check that the file exists, and that it is valid YMAL.'
35
+ return false
36
+ end
37
+
38
+ # Load Environment Configuration
39
+ env = env.downcase
40
+
41
+ @log.info ''
42
+ @log.info "SmartNotify Environment: #{env}"
43
+
44
+ config = external_config[env]
45
+ if config.nil?
46
+ @log.error 'Configuration does not contain configuration for specified environment.'
47
+ return false
48
+ end
49
+
50
+ # Load Template Configuration
51
+ template_config = config[template]
52
+ if template_config.nil?
53
+ @log.error "Template '#{template}' not found."
54
+ return false
55
+ end
56
+
57
+ # Configure Development Flags
58
+ config['global']['dryrun'] = dryrun
59
+
60
+
61
+ # Load JSON
62
+ begin
63
+ template_data = JSON.parse(json)
64
+ rescue JSON::ParserError => e
65
+ puts 'ERROR: JSON provided is unable to be parsed.'
66
+ return false
67
+ end
68
+
69
+ # Prepare Module Configuration
70
+ module_config = Hash.new
71
+ module_config[:config] = template_config
72
+ module_config[:data] = template_data
73
+ module_config[:global] = config['global']
74
+
75
+ # Ensure Required Fields Present
76
+ unless module_config[:config]['required_fields'].nil?
77
+ module_config[:config]['required_fields'].each do |field|
78
+ if module_config[:data][field].nil?
79
+ @log.error "JSON provided is missing required field '#{field}'"
80
+ return false
81
+ end
82
+ end
83
+ end
84
+
85
+ if module_config[:config]['module'] == 'rotation_emailer'
86
+ require_relative 'modules/rotation_emailer/rotation_emailer'
87
+ elsif module_config[:config]['module'] == 'slack_notifier'
88
+ require_relative 'modules/slack_notifier/slack_notifier'
89
+ else
90
+ @log.error "'#{module_config[:config]['module']}' module does not exist."
91
+ @log.error 'Ensure the correct module name is defined in the configuration.'
92
+ return false
93
+ end
94
+
95
+ # Run Module
96
+ NotificationModule.new(module_config).run
97
+ end
98
+ end
99
+
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smartnotify2
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Performance Improvement Dev
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: mail
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: logging
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: slack-notifier
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.3'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.3'
55
+ description: Utility for sending various types of notifications via a common configurable
56
+ interface.
57
+ email:
58
+ - kristopher.williams@cerner.com
59
+ executables: []
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - README.md
64
+ - lib/config/config.yml
65
+ - lib/modules/rotation_emailer/README.md
66
+ - lib/modules/rotation_emailer/rotation_emailer.rb
67
+ - lib/modules/slack_notifier/README.md
68
+ - lib/modules/slack_notifier/slack_notifier.rb
69
+ - lib/smartnotify.rb
70
+ homepage: https://github.cerner.com/PHPerfImp/smartnotify
71
+ licenses: []
72
+ metadata: {}
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ required_rubygems_version: !ruby/object:Gem::Requirement
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ version: '0'
87
+ requirements: []
88
+ rubygems_version: 3.0.3
89
+ signing_key:
90
+ specification_version: 4
91
+ summary: Common interface notification utility
92
+ test_files: []