chook 1.0.0.b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +174 -0
- data/README.md +259 -0
- data/bin/chook-server +28 -0
- data/data/sample_handlers/RestAPIOperation-executable +91 -0
- data/data/sample_handlers/RestAPIOperation.rb +45 -0
- data/data/sample_handlers/SmartGroupComputerMembershipChange-executable +47 -0
- data/data/sample_handlers/SmartGroupComputerMembershipChange.rb +33 -0
- data/data/sample_jsons/ComputerAdded.json +27 -0
- data/data/sample_jsons/ComputerCheckIn.json +27 -0
- data/data/sample_jsons/ComputerInventoryCompleted.json +27 -0
- data/data/sample_jsons/ComputerPolicyFinished.json +27 -0
- data/data/sample_jsons/ComputerPushCapabilityChanged.json +27 -0
- data/data/sample_jsons/JSSShutdown.json +14 -0
- data/data/sample_jsons/JSSStartup.json +14 -0
- data/data/sample_jsons/MobileDeviceCheckIn.json +26 -0
- data/data/sample_jsons/MobileDeviceCommandCompleted.json +26 -0
- data/data/sample_jsons/MobileDeviceEnrolled.json +26 -0
- data/data/sample_jsons/MobileDevicePushSent.json +26 -0
- data/data/sample_jsons/MobileDeviceUnEnrolled.json +26 -0
- data/data/sample_jsons/PatchSoftwareTitleUpdated.json +14 -0
- data/data/sample_jsons/PushSent.json +11 -0
- data/data/sample_jsons/README +4 -0
- data/data/sample_jsons/RestAPIOperation.json +15 -0
- data/data/sample_jsons/SCEPChallenge.json +10 -0
- data/data/sample_jsons/SmartGroupComputerMembershipChange.json +13 -0
- data/data/sample_jsons/SmartGroupMobileDeviceMembershipChange.json +13 -0
- data/lib/chook.rb +38 -0
- data/lib/chook/configuration.rb +198 -0
- data/lib/chook/event.rb +153 -0
- data/lib/chook/event/handled_event.rb +154 -0
- data/lib/chook/event/handled_event/handlers.rb +206 -0
- data/lib/chook/event/test_event.rb +140 -0
- data/lib/chook/event_handling.rb +40 -0
- data/lib/chook/event_testing.rb +43 -0
- data/lib/chook/foundation.rb +33 -0
- data/lib/chook/handled_events.rb +33 -0
- data/lib/chook/handled_subjects.rb +33 -0
- data/lib/chook/procs.rb +46 -0
- data/lib/chook/server.rb +121 -0
- data/lib/chook/server/routes.rb +27 -0
- data/lib/chook/server/routes/handle_webhook_event.rb +39 -0
- data/lib/chook/server/routes/home.rb +37 -0
- data/lib/chook/subject.rb +143 -0
- data/lib/chook/subject/computer.rb +121 -0
- data/lib/chook/subject/handled_subject.rb +84 -0
- data/lib/chook/subject/jss.rb +56 -0
- data/lib/chook/subject/mobile_device.rb +115 -0
- data/lib/chook/subject/patch_software_title_update.rb +55 -0
- data/lib/chook/subject/push.rb +38 -0
- data/lib/chook/subject/randomizers.rb +506 -0
- data/lib/chook/subject/rest_api_operation.rb +62 -0
- data/lib/chook/subject/samplers.rb +360 -0
- data/lib/chook/subject/scep_challenge.rb +32 -0
- data/lib/chook/subject/smart_group.rb +50 -0
- data/lib/chook/subject/test_subject.rb +195 -0
- data/lib/chook/subject/validators.rb +117 -0
- data/lib/chook/test_events.rb +33 -0
- data/lib/chook/test_subjects.rb +33 -0
- data/lib/chook/version.rb +32 -0
- metadata +129 -0
@@ -0,0 +1,154 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
require 'chook/event/handled_event/handlers'
|
27
|
+
|
28
|
+
#
|
29
|
+
module Chook
|
30
|
+
|
31
|
+
# Load sample JSON files, one per event type
|
32
|
+
@sample_jsons = {}
|
33
|
+
base_dir = Pathname.new(__FILE__)
|
34
|
+
data_dir = base_dir.parent.parent.parent.parent
|
35
|
+
sample_json_dir = Pathname.new(data_dir.to_s + '/data/sample_jsons')
|
36
|
+
sample_json_dir.children.each do |jf|
|
37
|
+
event = jf.basename.to_s.chomp(jf.extname).to_sym
|
38
|
+
@sample_jsons[event] = jf.read
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.sample_jsons
|
42
|
+
@sample_jsons
|
43
|
+
end
|
44
|
+
|
45
|
+
# An event that has been recieved and needs to be handled.
|
46
|
+
#
|
47
|
+
# This is the parent class to all of the classes in the
|
48
|
+
# Chook::HandledEvents module, which are dynamically defined when this
|
49
|
+
# file is loaded.
|
50
|
+
#
|
51
|
+
# All constants, methods, and attributes that are common to HandledEvent
|
52
|
+
# classes are defined here, including the interaction with the Handlers
|
53
|
+
# module.
|
54
|
+
#
|
55
|
+
# Subclasses are automatically generated from the keys and values of
|
56
|
+
# Chook::Event::EVENTS
|
57
|
+
#
|
58
|
+
# Each subclass will have a constant SUBJECT_CLASS containing the
|
59
|
+
# class of their #subject attribute.
|
60
|
+
#
|
61
|
+
class HandledEvent < Chook::Event
|
62
|
+
|
63
|
+
#### Class Methods
|
64
|
+
|
65
|
+
# Given some raw_json from the jss, create and return the correct
|
66
|
+
# HandledEvent subclass
|
67
|
+
|
68
|
+
# For each event type in Chook::Event::EVENTS
|
69
|
+
# generate a class for it, set its SUBJECT_CLASS constant
|
70
|
+
# and add it to the HandledEvents module.
|
71
|
+
#
|
72
|
+
# @return [void]
|
73
|
+
#
|
74
|
+
def self.generate_classes
|
75
|
+
Chook::Event::EVENTS.each do |class_name, subject|
|
76
|
+
next if Chook::HandledEvents.const_defined? class_name
|
77
|
+
|
78
|
+
# make the new HandledEvent subclass
|
79
|
+
the_class = Class.new(Chook::HandledEvent)
|
80
|
+
|
81
|
+
# Set its EVENT_NAME constant, which is used
|
82
|
+
# for finding it's handlers, among other things.
|
83
|
+
the_class.const_set Chook::Event::EVENT_NAME_CONST, class_name
|
84
|
+
|
85
|
+
# Set its SUBJECT_CLASS constant to the appropriate
|
86
|
+
# class in the HandledSubjects module.
|
87
|
+
the_class.const_set Chook::Event::SUBJECT_CLASS_CONST, Chook::HandledSubjects.const_get(subject)
|
88
|
+
|
89
|
+
# Add the new class to the HandledEvents module.
|
90
|
+
Chook::HandledEvents.const_set(class_name, the_class)
|
91
|
+
end # each classname, subject
|
92
|
+
end # self.generate_classes
|
93
|
+
|
94
|
+
# Given the raw json from the JSS webhook,
|
95
|
+
# create an object of the correct Event subclass
|
96
|
+
#
|
97
|
+
# @param [String] raw_event_json The JSON http POST content from the JSS
|
98
|
+
#
|
99
|
+
# @return [JSSWebHooks::Event subclass] the Event subclass matching the event
|
100
|
+
#
|
101
|
+
def self.parse_event(raw_event_json)
|
102
|
+
event_json = JSON.parse(raw_event_json, symbolize_names: true)
|
103
|
+
event_name = event_json[:webhook][:webhookEvent]
|
104
|
+
Chook::HandledEvents.const_get(event_name).new raw_event_json
|
105
|
+
end
|
106
|
+
|
107
|
+
#### Attributes
|
108
|
+
|
109
|
+
# @return [Array<Proc,Pathname>] the handlers defined for this event.
|
110
|
+
# Each is either a proc, in which case it is called with this
|
111
|
+
# instance as its sole paramter, or its a Pathname to an executable
|
112
|
+
# file, in which case the @raw_json is passed to its stdin.
|
113
|
+
# See the Chook::HandledEvent::Handlers module.
|
114
|
+
attr_reader :handlers
|
115
|
+
|
116
|
+
#### Constructor
|
117
|
+
|
118
|
+
# Handled Events are always built from raw_json.
|
119
|
+
#
|
120
|
+
def initialize(raw_event_json)
|
121
|
+
super raw_json: raw_event_json
|
122
|
+
end # init
|
123
|
+
|
124
|
+
def handle
|
125
|
+
handlers = Handlers.handlers[self.class.const_get(Chook::Event::EVENT_NAME_CONST)]
|
126
|
+
handlers.each do |handler|
|
127
|
+
case handler
|
128
|
+
when Pathname
|
129
|
+
pipe_to_executable handler
|
130
|
+
when Proc
|
131
|
+
handle_with_proc handler
|
132
|
+
end # case
|
133
|
+
end # @handlers.each do |handler|
|
134
|
+
|
135
|
+
# the handle method should return a string,
|
136
|
+
# which is the body of the HTTP result for
|
137
|
+
# POSTing the event
|
138
|
+
"Processed by #{handlers.count} handlers\n"
|
139
|
+
end # def handle
|
140
|
+
|
141
|
+
# TODO: Add something here that cleans up old threads and forks
|
142
|
+
def pipe_to_executable(handler)
|
143
|
+
_thread = Thread.new do
|
144
|
+
IO.popen([handler.to_s], 'w') { |h| h.puts @raw_json }
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def handle_with_proc(handler)
|
149
|
+
_thread = Thread.new { handler.call self }
|
150
|
+
end
|
151
|
+
|
152
|
+
end # class HandledEvent
|
153
|
+
|
154
|
+
end # module
|
@@ -0,0 +1,206 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
module Chook
|
26
|
+
|
27
|
+
# This method is used by the Ruby event-handler files.
|
28
|
+
#
|
29
|
+
# Loading them should call this method and pass in a block
|
30
|
+
# with one parameter: a Chook::HandledEvent subclass instance.
|
31
|
+
#
|
32
|
+
# The block is then converted to a Proc instance in @loaded_event_handler
|
33
|
+
# and from there can be stored for use by the event identified by the filename.
|
34
|
+
#
|
35
|
+
# NOTE: the files should be read with 'load' not 'require', so that they can
|
36
|
+
# be re-loaded as needed
|
37
|
+
#
|
38
|
+
# @see_also Chook::load_handlers
|
39
|
+
#
|
40
|
+
# @param [Block] block the block to be used as an event handler
|
41
|
+
#
|
42
|
+
# @yieldparam [JSS::WebHooks::Event subclass] The event to be handled
|
43
|
+
#
|
44
|
+
# @return [Proc] the block converted to a Proc
|
45
|
+
#
|
46
|
+
def self.event_handler(&block)
|
47
|
+
HandledEvent::Handlers.loaded_handler = Proc.new(&block)
|
48
|
+
end
|
49
|
+
|
50
|
+
# the server class
|
51
|
+
class HandledEvent < Event
|
52
|
+
|
53
|
+
# The Handlers namespace module
|
54
|
+
module Handlers
|
55
|
+
|
56
|
+
# Module Constants
|
57
|
+
############################
|
58
|
+
|
59
|
+
DEFAULT_HANDLER_DIR = '/Library/Application Support/Chook'.freeze
|
60
|
+
|
61
|
+
# Module Instance Variables, & accessors
|
62
|
+
############################
|
63
|
+
|
64
|
+
# This holds the most recently loaded Proc handler
|
65
|
+
# until it can be stored in the @handlers Hash
|
66
|
+
@loaded_handler = nil
|
67
|
+
|
68
|
+
# Getter for @loaded_handler
|
69
|
+
#
|
70
|
+
# @return [Proc,nil] the most recent Proc loaded from a handler file.
|
71
|
+
# destined for storage in @handlers
|
72
|
+
#
|
73
|
+
def self.loaded_handler
|
74
|
+
@loaded_handler
|
75
|
+
end
|
76
|
+
|
77
|
+
# Setter for @loaded_event_handler
|
78
|
+
#
|
79
|
+
# @param a_proc [Proc] a Proc object for storage in @handlers
|
80
|
+
#
|
81
|
+
def self.loaded_handler=(a_proc)
|
82
|
+
@loaded_handler = a_proc
|
83
|
+
end
|
84
|
+
|
85
|
+
# A hash of loaded handlers.
|
86
|
+
# Keys are Strings - the name of the events handled
|
87
|
+
# Values are Arrays of either Procs, or Pathnames to executable files.
|
88
|
+
# See the .handlers getter Methods
|
89
|
+
@handlers = {}
|
90
|
+
|
91
|
+
# Getter for @event_handlers
|
92
|
+
#
|
93
|
+
# @return [Hash{String => Array}] a mapping of Event Names as the come from
|
94
|
+
# the JSS to an Array of handlers for the event. The handlers are either
|
95
|
+
# Proc objects to call from within ruby, or Pathnames to executable files
|
96
|
+
# which will take raw JSON on stdin.
|
97
|
+
def self.handlers
|
98
|
+
@handlers
|
99
|
+
end
|
100
|
+
|
101
|
+
# Module Methods
|
102
|
+
############################
|
103
|
+
|
104
|
+
# Load all the event handlers from the handler_dir or an arbitrary dir.
|
105
|
+
#
|
106
|
+
# @param from_dir [String, Pathname] directory from which to load the
|
107
|
+
# handlers. Defaults to CONFIG.handler_dir or DEFAULT_HANDLER_DIR if
|
108
|
+
# config is unset
|
109
|
+
#
|
110
|
+
# @param reload [Boolean] should we reload handlers if they've already
|
111
|
+
# been loaded?
|
112
|
+
#
|
113
|
+
# @return [void]
|
114
|
+
#
|
115
|
+
def self.load_handlers(from_dir: Chook::CONFIG.handler_dir, reload: false)
|
116
|
+
from_dir ||= DEFAULT_HANDLER_DIR
|
117
|
+
if reload
|
118
|
+
@handlers_loaded_from = nil
|
119
|
+
@handlers = {}
|
120
|
+
@loaded_handler = nil
|
121
|
+
end
|
122
|
+
|
123
|
+
handler_dir = Pathname.new(from_dir)
|
124
|
+
return unless handler_dir.directory? && handler_dir.readable?
|
125
|
+
|
126
|
+
handler_dir.children.each do |handler_file|
|
127
|
+
load_handler(handler_file) if handler_file.file? && handler_file.readable?
|
128
|
+
end
|
129
|
+
|
130
|
+
@handlers_loaded_from = handler_dir
|
131
|
+
@handlers.values.flatten.size
|
132
|
+
end # load handlers
|
133
|
+
|
134
|
+
# Load an event handler from a file.
|
135
|
+
# Handler files must begin with the name of the event they handle,
|
136
|
+
# e.g. ComputerAdded, followed by: nothing, a dot, a dash, or
|
137
|
+
# and underscore. Case doesn't matter.
|
138
|
+
# So all of these are OK:
|
139
|
+
# ComputerAdded
|
140
|
+
# computeradded.sh
|
141
|
+
# COMPUTERAdded_notify_team
|
142
|
+
# Computeradded-update-ldap
|
143
|
+
# There can be as many as desired for each event.
|
144
|
+
#
|
145
|
+
# Each must be either:
|
146
|
+
# - An executable file, which will have the raw JSON from the JSS piped
|
147
|
+
# to it's stdin when executed
|
148
|
+
# or
|
149
|
+
# - A non-executable file of ruby code like this:
|
150
|
+
# Chook.event_handler do |event|
|
151
|
+
# # your code goes here.
|
152
|
+
# end
|
153
|
+
#
|
154
|
+
# (see the Chook README for details about writing the ruby handlers)
|
155
|
+
#
|
156
|
+
# @param from_file [Pathname] the file from which to load the handler
|
157
|
+
#
|
158
|
+
# @return [void]
|
159
|
+
#
|
160
|
+
def self.load_handler(from_file)
|
161
|
+
handler_file = Pathname.new from_file
|
162
|
+
event_name = event_name_from_handler_filename(handler_file)
|
163
|
+
return unless event_name
|
164
|
+
|
165
|
+
# create an array for this event's handlers, if needed
|
166
|
+
@handlers[event_name] ||= []
|
167
|
+
|
168
|
+
if handler_file.executable?
|
169
|
+
# store as a Pathname, we'll pipe JSON to it
|
170
|
+
unless @handlers[event_name].include? handler_file
|
171
|
+
@handlers[event_name] << handler_file
|
172
|
+
puts "===> Loaded executable handler file '#{handler_file.basename}'"
|
173
|
+
end
|
174
|
+
return
|
175
|
+
end
|
176
|
+
|
177
|
+
# load the file. If written correctly, it will
|
178
|
+
# put a Proc into @loaded_handler
|
179
|
+
load handler_file.to_s
|
180
|
+
if @loaded_handler
|
181
|
+
@handlers[event_name] << @loaded_handler
|
182
|
+
puts "===> Loaded internal handler file '#{handler_file.basename}'"
|
183
|
+
@loaded_handler = nil
|
184
|
+
else
|
185
|
+
puts "===> FAILED loading internal handler file '#{handler_file.basename}'"
|
186
|
+
end
|
187
|
+
end # self.load_handler(handler_file)
|
188
|
+
|
189
|
+
# Given a handler filename, return the event name it wants to handle
|
190
|
+
#
|
191
|
+
# @param [Pathname] filename The filename from which to glean the
|
192
|
+
# event name.
|
193
|
+
#
|
194
|
+
# @return [String,nil] The matching event name or nil if no match
|
195
|
+
#
|
196
|
+
def self.event_name_from_handler_filename(filename)
|
197
|
+
@event_names ||= Chook::Event::EVENTS.keys
|
198
|
+
desired_event_name = filename.basename.to_s.split(/\.|-|_/).first
|
199
|
+
@event_names.select { |n| desired_event_name.casecmp(n).zero? }.first
|
200
|
+
end
|
201
|
+
|
202
|
+
end # module Handler
|
203
|
+
|
204
|
+
end # class handledevent
|
205
|
+
|
206
|
+
end # module
|
@@ -0,0 +1,140 @@
|
|
1
|
+
### Copyright 2017 Pixar
|
2
|
+
|
3
|
+
###
|
4
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
5
|
+
### with the following modification; you may not use this file except in
|
6
|
+
### compliance with the Apache License and the following modification to it:
|
7
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
8
|
+
###
|
9
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
10
|
+
### names, trademarks, service marks, or product names of the Licensor
|
11
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
12
|
+
### the License and to reproduce the content of the NOTICE file.
|
13
|
+
###
|
14
|
+
### You may obtain a copy of the Apache License at
|
15
|
+
###
|
16
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
17
|
+
###
|
18
|
+
### Unless required by applicable law or agreed to in writing, software
|
19
|
+
### distributed under the Apache License with the above modification is
|
20
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
21
|
+
### KIND, either express or implied. See the Apache License for the specific
|
22
|
+
### language governing permissions and limitations under the Apache License.
|
23
|
+
###
|
24
|
+
###
|
25
|
+
|
26
|
+
module Chook
|
27
|
+
|
28
|
+
# An event that will be sent to a Webhook Server, simulating
|
29
|
+
# one from the JSS.
|
30
|
+
#
|
31
|
+
# This is the parent class to all of the classes in the
|
32
|
+
# Chook::TestEvents module, which are dynamically defined when this
|
33
|
+
# file is loaded.
|
34
|
+
#
|
35
|
+
# All constants, methods, and attributes that are common to TestEvent
|
36
|
+
# classes are defined here.
|
37
|
+
#
|
38
|
+
class TestEvent < Chook::Event
|
39
|
+
|
40
|
+
EVENT_ATTRIBUTES = %w(webhook_id webhook_name subject).freeze
|
41
|
+
|
42
|
+
# For each event type in Chook::Event::EVENTS.keys
|
43
|
+
# generate a TestEvent class for it, set its SUBJECT_CLASS constant
|
44
|
+
# and add it to the TestEvents module.
|
45
|
+
#
|
46
|
+
# @return [void]
|
47
|
+
#
|
48
|
+
def self.generate_classes
|
49
|
+
Chook::Event::EVENTS.each do |classname, subject|
|
50
|
+
next if Chook::TestEvents.const_defined? classname
|
51
|
+
# make the new TestEvent subclass
|
52
|
+
new_class = Class.new(Chook::TestEvent) do
|
53
|
+
# Setters & Getters
|
54
|
+
EVENT_ATTRIBUTES.each do |attribute|
|
55
|
+
# Getter
|
56
|
+
attr_reader attribute
|
57
|
+
# Setter
|
58
|
+
if attribute == 'subject'
|
59
|
+
define_method("#{attribute}=") do |new_val|
|
60
|
+
raise "Invalid TestSubject: Chook::TestEvents::#{classname} requires a Chook::TestSubjects::#{EVENTS[classname]}" unless Chook::Validators.send(:valid_test_subject, classname, new_val)
|
61
|
+
instance_variable_set(('@' + attribute.to_s), new_val)
|
62
|
+
end # end define_method
|
63
|
+
else
|
64
|
+
define_method("#{attribute}=") do |new_val|
|
65
|
+
instance_variable_set(('@' + attribute.to_s), new_val)
|
66
|
+
end # end define_method
|
67
|
+
end
|
68
|
+
end # end EVENT_ATTRIBUTES.each do |attribute|
|
69
|
+
end # end new_class
|
70
|
+
|
71
|
+
# Set its EVENT_NAME constant
|
72
|
+
new_class.const_set Chook::TestEvent::EVENT_NAME_CONST, classname
|
73
|
+
|
74
|
+
# Set its SUBJECT_CLASS constant to the appropriate
|
75
|
+
# class in the TestEvents module.
|
76
|
+
new_class.const_set Chook::TestEvent::SUBJECT_CLASS_CONST, Chook::TestSubjects.const_get(subject)
|
77
|
+
|
78
|
+
# Add the new class to the HandledEvents module.
|
79
|
+
Chook::TestEvents.const_set(classname, new_class)
|
80
|
+
end # each classname, subject
|
81
|
+
end # self.generate_classes
|
82
|
+
|
83
|
+
# json_hash
|
84
|
+
# Used by the fire method
|
85
|
+
#
|
86
|
+
# @return [Hash] A JSON Event payload formatted as a Hash.
|
87
|
+
#
|
88
|
+
def json_hash
|
89
|
+
raw_hash_form = {}
|
90
|
+
raw_hash_form['webhook'.to_sym] = { 'webhookEvent'.to_sym => self.class.to_s.split('::')[-1] }
|
91
|
+
EVENT_ATTRIBUTES.each do |json_attribute|
|
92
|
+
next if json_attribute.include? 'json'
|
93
|
+
if json_attribute == 'subject'
|
94
|
+
raw_hash_form['event'.to_sym] = instance_variable_get('@' + json_attribute).json_hash
|
95
|
+
else
|
96
|
+
json_hash_attribute = json_attribute.split('webhook_')[1] || json_attribute
|
97
|
+
nested_hash = Hash.new do |hash, key|
|
98
|
+
hash[key] = {}
|
99
|
+
end # end nested_hash
|
100
|
+
nested_hash[json_hash_attribute.to_sym] = instance_variable_get('@' + json_attribute)
|
101
|
+
raw_hash_form['webhook'.to_sym][nested_hash.keys[0]] = nested_hash[nested_hash.keys[0]]
|
102
|
+
end
|
103
|
+
end # end EVENT_ATTRIBUTES.each do |json_attribute|
|
104
|
+
raw_hash_form # This is the structural equivalent of the Chook::Event @json_hash form
|
105
|
+
end # end json_hash
|
106
|
+
|
107
|
+
# fire
|
108
|
+
#
|
109
|
+
# @param [String] server_url The URL of a server that can handle an Event
|
110
|
+
# @return [void]
|
111
|
+
#
|
112
|
+
def fire(server_url)
|
113
|
+
raise 'Please provide a destination server URL' unless server_url
|
114
|
+
uri = URI.parse(server_url)
|
115
|
+
raise 'Please provide a valid destination server URL' if uri.host.nil?
|
116
|
+
data = json_hash.to_json # This is the structural equivalent of the Chook::Event @raw_json form
|
117
|
+
http_connection = Net::HTTP.new uri.host, uri.port
|
118
|
+
http_connection.post(uri, data)
|
119
|
+
end # end fire
|
120
|
+
|
121
|
+
# initialize
|
122
|
+
# The optional argument is a Hash with the appropriate keys defiend
|
123
|
+
#
|
124
|
+
# @param [Hash] event_data nil or Hash
|
125
|
+
# @return [TestEvent] A new TestEvents subclass object
|
126
|
+
#
|
127
|
+
def initialize(event_data = nil)
|
128
|
+
if event_data
|
129
|
+
event_data.each do |key, value|
|
130
|
+
next unless EVENT_ATTRIBUTES.include? key
|
131
|
+
instance_variable_set(('@' + key.to_s), value)
|
132
|
+
end # event_data.each
|
133
|
+
else
|
134
|
+
EVENT_ATTRIBUTES.each { |attribute| instance_variable_set(('@' + attribute.to_s), nil) }
|
135
|
+
end # end if event_data
|
136
|
+
end # end init
|
137
|
+
|
138
|
+
end # class TestEvent
|
139
|
+
|
140
|
+
end # module
|