approval_hub 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +79 -0
- data/lib/approval_hub.rb +23 -0
- data/lib/approval_hub/api.rb +255 -0
- data/lib/approval_hub/detail.rb +31 -0
- data/lib/approval_hub/request.rb +19 -0
- metadata +65 -0
data/README.md
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
Approval Hub API
|
2
|
+
================
|
3
|
+
A simple library for talking to the Enterprise Approval Hub.
|
4
|
+
See the rdoc for detailed usage instructions
|
5
|
+
|
6
|
+
quick start
|
7
|
+
-----------
|
8
|
+
install the gem
|
9
|
+
|
10
|
+
gem install approval_hub
|
11
|
+
|
12
|
+
require and use
|
13
|
+
|
14
|
+
require 'approval_hub'
|
15
|
+
|
16
|
+
# default uat instance
|
17
|
+
api = ApprovalHub::API.uat(username,password)
|
18
|
+
|
19
|
+
# default prod instance
|
20
|
+
api = ApprovalHub::API.prod(username,password)
|
21
|
+
|
22
|
+
# register an approval
|
23
|
+
api.register do |r|
|
24
|
+
r.request_id = "001"
|
25
|
+
r.requestor_id = "neilcuk"
|
26
|
+
r.approver_id = "kasperdulles[,others..]"
|
27
|
+
r.short_description = "A summary"
|
28
|
+
r.long_description = "A lengthier expose"
|
29
|
+
r.url = "http://url.to.source/system"
|
30
|
+
end
|
31
|
+
|
32
|
+
# get details
|
33
|
+
api.details(request_id)
|
34
|
+
|
35
|
+
# get approval status
|
36
|
+
api.status(request_id)
|
37
|
+
|
38
|
+
# approve a request
|
39
|
+
api.approve(request_id, approver_id)
|
40
|
+
|
41
|
+
# cancel a request
|
42
|
+
api.cancel(request_id, approver_id)
|
43
|
+
|
44
|
+
# decline a request
|
45
|
+
api.decline(request_id, approver_id)
|
46
|
+
|
47
|
+
troubleshooting
|
48
|
+
---------------
|
49
|
+
All methods come with a bang version *method!* which
|
50
|
+
will throw relevant exceptions
|
51
|
+
|
52
|
+
If you want to see what is happening with the http
|
53
|
+
session, grab an API instance with debugging enabled
|
54
|
+
|
55
|
+
api = ApprovalHub::API.uat_with_debugging(username,password)
|
56
|
+
# or
|
57
|
+
api = ApprovalHub::API.prod_with_debugging(username,password)
|
58
|
+
|
59
|
+
The URL's for each of the instances are set in the root
|
60
|
+
of the module. It's unlikely these will change. If for
|
61
|
+
some reason they do and I can't get around to updating
|
62
|
+
the package you can use the default constructor
|
63
|
+
|
64
|
+
# include a url and boolean indicating whether to turn on
|
65
|
+
# http session debugging
|
66
|
+
api = ApprovalHub::API.new(url,username,password,enable_debugging)
|
67
|
+
|
68
|
+
|
69
|
+
The Enterprise Approval Hub facilitates centralised
|
70
|
+
sign-off for any kind of request. See
|
71
|
+
http://wiki.office.aol.com/wiki/ApprovalKiosk
|
72
|
+
|
73
|
+
acknowledgements
|
74
|
+
----------------
|
75
|
+
Thanks to [HTTParty](https://github.com/jnunemaker/httparty) for making http fun!
|
76
|
+
|
77
|
+
bugs
|
78
|
+
----
|
79
|
+
Send me an email
|
data/lib/approval_hub.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
module ApprovalHub
|
2
|
+
# approval hub API interfaces
|
3
|
+
REGISTER = "/Register"
|
4
|
+
DETAILS = "/getDetails"
|
5
|
+
DECLINE = "/DeclineRequest"
|
6
|
+
APPROVE = "/ApproveRequest"
|
7
|
+
CANCEL = "/deleteRequest"
|
8
|
+
|
9
|
+
# approval hub status responses
|
10
|
+
PENDING = "Open"
|
11
|
+
APPROVED = "Approve"
|
12
|
+
REJECTED = "Decline"
|
13
|
+
NOT_FOUND = "Not Found"
|
14
|
+
|
15
|
+
# default URLs
|
16
|
+
URL_UAT = "http://csoweb-m01.office.aol.com:8080/EnterpriseApprovalWS/hub/system"
|
17
|
+
URL_PROD = "https://approvals-hub.office.aol.com/EnterpriseApprovalWS/hub/system"
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'approval_hub/request'
|
21
|
+
require 'approval_hub/detail'
|
22
|
+
require 'approval_hub/api'
|
23
|
+
|
@@ -0,0 +1,255 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module ApprovalHub
|
4
|
+
#
|
5
|
+
# The ApprovalHub API
|
6
|
+
#
|
7
|
+
class API
|
8
|
+
include HTTParty
|
9
|
+
|
10
|
+
class << self
|
11
|
+
|
12
|
+
# get an instance of the uat hub
|
13
|
+
# requires a username and password
|
14
|
+
#
|
15
|
+
def uat(username, password)
|
16
|
+
new(URL_UAT,username,password)
|
17
|
+
end
|
18
|
+
|
19
|
+
# get an instance of the prod hub
|
20
|
+
# requires a username and password
|
21
|
+
#
|
22
|
+
def prod(username, password)
|
23
|
+
new(URL_PROD,username,password)
|
24
|
+
end
|
25
|
+
|
26
|
+
# get an instance of the uat hub with session debugging
|
27
|
+
# requires a username and password
|
28
|
+
#
|
29
|
+
def uat_with_debugging(username,password)
|
30
|
+
new(URL_UAT,username,password, true)
|
31
|
+
end
|
32
|
+
|
33
|
+
# get an instance of the prod hub with session debugging
|
34
|
+
# requires a username and password
|
35
|
+
#
|
36
|
+
def prod_with_debugging(username,password)
|
37
|
+
new(URL_PROD,username,password, true)
|
38
|
+
end
|
39
|
+
|
40
|
+
# get an instance of your choosing
|
41
|
+
# requires a url, username, password and boolean indicating
|
42
|
+
# whether or not to turn on session debugging
|
43
|
+
#
|
44
|
+
def custom_config(config={})
|
45
|
+
raise(ArgumentError, "config cannot be empty") if config.empty?
|
46
|
+
new(config["url"], config["username"], config["password"], config["with_debugging"])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def initialize(url, username, password, with_debugging=false)
|
51
|
+
raise ArgumentError if url.nil? || username.nil? || password.nil?
|
52
|
+
unless url.nil?
|
53
|
+
@uri = url
|
54
|
+
end
|
55
|
+
@auth = {:user => username, :pw => password}
|
56
|
+
if with_debugging
|
57
|
+
self.class.debug_output $stderr
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Register your approval request with the hub
|
62
|
+
# Registration takes a Request object or a block
|
63
|
+
# returns true is successful else false
|
64
|
+
#
|
65
|
+
# example1:
|
66
|
+
# api = ApprovalHub::API.uat("someuser","somepwd")
|
67
|
+
# api.register do |r|
|
68
|
+
# r.request_id = "001"
|
69
|
+
# r.requestor_id = "neilcuk"
|
70
|
+
# r.approver_id = "kasperdulles[,others..]"
|
71
|
+
# r.short_description = "A summary"
|
72
|
+
# r.long_description = "A lengthier expose"
|
73
|
+
# r.url = "http://url.to.source/system"
|
74
|
+
# end
|
75
|
+
#
|
76
|
+
# example2:
|
77
|
+
# api = ApprovalHub::API.uat("someuser","somepwd")
|
78
|
+
# r = ApprovalHub::Request.new
|
79
|
+
# r.request_id = "001"
|
80
|
+
# r.requestor_id = "neilcuk"
|
81
|
+
# r.approver_id = "kasperdulles[,others..]"
|
82
|
+
# r.short_description = "A summary"
|
83
|
+
# r.long_description = "A lengthier expose"
|
84
|
+
# r.url = "http://url.to.source/system"
|
85
|
+
# api.register(r)
|
86
|
+
#
|
87
|
+
def register(request = Request.new, &block)
|
88
|
+
register!(request,&block) rescue false
|
89
|
+
end
|
90
|
+
|
91
|
+
# Same as register but will throw an exception
|
92
|
+
# if it encounteres an error
|
93
|
+
#
|
94
|
+
def register!(request = Request.new, &block)
|
95
|
+
begin
|
96
|
+
options = assemble_request(request,&block)
|
97
|
+
request = self.class.get( @uri + REGISTER, options )
|
98
|
+
rescue Exception => e
|
99
|
+
raise e, "Unable to register approval request"
|
100
|
+
end
|
101
|
+
if request.response.code != "200"
|
102
|
+
raise "Approval hub denied request registration with code #{request.response.code}"
|
103
|
+
end
|
104
|
+
true
|
105
|
+
end
|
106
|
+
|
107
|
+
# Retrieves a Detail object from the hub
|
108
|
+
# requires a request_id
|
109
|
+
# returns false if an error occured
|
110
|
+
# takes an optional block which will be passed
|
111
|
+
# the detail object
|
112
|
+
#
|
113
|
+
def details(request_id, &block)
|
114
|
+
details!(request_id, &block) rescue false
|
115
|
+
end
|
116
|
+
|
117
|
+
# Same as details but will throw an exception
|
118
|
+
# if it encounters an error
|
119
|
+
#
|
120
|
+
def details!(request_id, &block)
|
121
|
+
raise "Request ID cannot be nil" if request_id.nil?
|
122
|
+
begin
|
123
|
+
options = {
|
124
|
+
:query => {
|
125
|
+
:requestID => request_id
|
126
|
+
}.merge!(@auth)
|
127
|
+
}
|
128
|
+
detail = self.class.get( @uri + DETAILS, options )
|
129
|
+
if detail["response"]["status"] == 200
|
130
|
+
detail = Detail.new(detail["ApprovalList"][0])
|
131
|
+
if block_given?
|
132
|
+
yield detail
|
133
|
+
else
|
134
|
+
detail
|
135
|
+
end
|
136
|
+
else
|
137
|
+
raise ArgumentError, "request not found"
|
138
|
+
end
|
139
|
+
rescue Exception => e
|
140
|
+
raise e, "Unable to retrieve details for #{request_id}"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# Returns the status of the provided request id
|
145
|
+
# or false if some error occured
|
146
|
+
#
|
147
|
+
def status(request_id)
|
148
|
+
status!(request_id) rescue false
|
149
|
+
end
|
150
|
+
|
151
|
+
# Same as status but will throw an excption
|
152
|
+
# if it encounters an error
|
153
|
+
#
|
154
|
+
def status!(request_id)
|
155
|
+
detail = details!(request_id)
|
156
|
+
if detail.open?
|
157
|
+
"Pending Approval"
|
158
|
+
elsif detail.approved?
|
159
|
+
"Approved"
|
160
|
+
elsif detail.declined?
|
161
|
+
"Declined"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Approve an open request
|
166
|
+
# Returns true if successful else false
|
167
|
+
#
|
168
|
+
def approve_request(request_id, approver_id)
|
169
|
+
approve_request!(request_id,approver_id) rescue false
|
170
|
+
end
|
171
|
+
|
172
|
+
# Same as approve_request but will throw
|
173
|
+
# exception on error
|
174
|
+
#
|
175
|
+
def approve_request!(request_id, approver_id)
|
176
|
+
update_request(request_id,approver_id, ApprovalHub::APPROVE)
|
177
|
+
end
|
178
|
+
|
179
|
+
# Cancel an open request
|
180
|
+
# Returns true if successful else false
|
181
|
+
#
|
182
|
+
def cancel_request(request_id, approver_id)
|
183
|
+
cancel_request!(request_id,approver_id) rescue false
|
184
|
+
end
|
185
|
+
|
186
|
+
# Same as cancel_request but will throw
|
187
|
+
# exception on error
|
188
|
+
#
|
189
|
+
def cancel_request!(request_id, approver_id)
|
190
|
+
update_request(request_id,approver_id, ApprovalHub::CANCEL)
|
191
|
+
end
|
192
|
+
|
193
|
+
# decline an open request.
|
194
|
+
# Takes an optional reason for rejection
|
195
|
+
# Returns true if success else false
|
196
|
+
#
|
197
|
+
def decline_request(request_id, approver_id, reason=nil)
|
198
|
+
decline_request!(request_id,approver_id,reason) rescue false
|
199
|
+
end
|
200
|
+
|
201
|
+
# Same as decline_request but will throw
|
202
|
+
# exception on error
|
203
|
+
#
|
204
|
+
def decline_request!(request_id, approver_id, reason=nil)
|
205
|
+
update_request(request_id,approver_id, ApprovalHub::DECLINE,reason)
|
206
|
+
end
|
207
|
+
|
208
|
+
private
|
209
|
+
|
210
|
+
def update_request(request_id, approver_id, action, reason=nil)
|
211
|
+
options = {
|
212
|
+
:query => {
|
213
|
+
:requestID => request_id,
|
214
|
+
:actionedByCdid => approver_id,
|
215
|
+
:actionedByName => approver_id,
|
216
|
+
:actionedByWhen => Time.now.strftime("%Y-%m-%d %H:%M:%S"),
|
217
|
+
:reason => reason
|
218
|
+
}.merge!(@auth)
|
219
|
+
}
|
220
|
+
begin
|
221
|
+
response = self.class.get( @uri + action, options )
|
222
|
+
if response["status"] == 200
|
223
|
+
true
|
224
|
+
elsif response["status"] == 202
|
225
|
+
raise ArgumentError, "Request with id #{request_id} does not exist"
|
226
|
+
else
|
227
|
+
false
|
228
|
+
end
|
229
|
+
rescue Exception => e
|
230
|
+
raise e, "Unable to update approval request"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
def assemble_request(request,&block)
|
235
|
+
if block_given?
|
236
|
+
yield request
|
237
|
+
end
|
238
|
+
raise "approval request not valid" if not request.is_valid?
|
239
|
+
options ={
|
240
|
+
:query => {
|
241
|
+
:state =>'open', # default required during registration
|
242
|
+
:requestID => request.request_id,
|
243
|
+
:shortDescription => request.short_description,
|
244
|
+
:longDescription => request.long_description,
|
245
|
+
:url => request.url,
|
246
|
+
:requestorCdid => request.requestor_id,
|
247
|
+
:approverCdid => request.approver_id,
|
248
|
+
:requestTime => Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
249
|
+
}.merge!(@auth)
|
250
|
+
}
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ApprovalHub
|
2
|
+
class Detail
|
3
|
+
attr_reader :request_id, :long_description, :short_description
|
4
|
+
attr_reader :requestor_id, :approver_id, :url, :reason, :state
|
5
|
+
|
6
|
+
def initialize(hash={})
|
7
|
+
unless hash.empty?
|
8
|
+
@request_id = hash["requestID"]
|
9
|
+
@long_description = hash["longDescription"]
|
10
|
+
@short_description = hash["shortDescription"]
|
11
|
+
@requestor_id = hash["requestorCDID"]
|
12
|
+
@approver_id = hash["actionedByCDID"]
|
13
|
+
@url = hash["url"]
|
14
|
+
@reason = hash["reason"]
|
15
|
+
@state = hash["state"]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def approved?
|
20
|
+
not (state =~ /#{ApprovalHub::APPROVED}/i).nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def declined?
|
24
|
+
not (state =~ /#{ApprovalHub::REJECTED}/i).nil?
|
25
|
+
end
|
26
|
+
|
27
|
+
def open?
|
28
|
+
not (state =~ /#{ApprovalHub::PENDING}/i).nil?
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module ApprovalHub
|
2
|
+
# A Request is passed to the hub for registration
|
3
|
+
#
|
4
|
+
class Request
|
5
|
+
attr_accessor :request_id, :long_description, :short_description
|
6
|
+
attr_accessor :requestor_id, :approver_id, :url
|
7
|
+
|
8
|
+
# Will return false if fields have not been set
|
9
|
+
# TODO - return an errors hash stating why the request is not valid
|
10
|
+
def is_valid?
|
11
|
+
not request_id.nil? ||
|
12
|
+
long_description.nil? ||
|
13
|
+
short_description.nil? ||
|
14
|
+
requestor_id.nil? ||
|
15
|
+
approver_id.nil? ||
|
16
|
+
url.nil?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: approval_hub
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Neil Chambers
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-05-16 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: httparty
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
description: A library for interacting with the Enterprise Approval Kiosk
|
31
|
+
email: neil.chambers@teamaol.com
|
32
|
+
executables: []
|
33
|
+
extensions: []
|
34
|
+
extra_rdoc_files: []
|
35
|
+
files:
|
36
|
+
- lib/approval_hub/api.rb
|
37
|
+
- lib/approval_hub/detail.rb
|
38
|
+
- lib/approval_hub/request.rb
|
39
|
+
- lib/approval_hub.rb
|
40
|
+
- README.md
|
41
|
+
homepage: http://wiki.office.aol.com/wiki/ApprovalKiosk
|
42
|
+
licenses: []
|
43
|
+
post_install_message:
|
44
|
+
rdoc_options: []
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
none: false
|
49
|
+
requirements:
|
50
|
+
- - ! '>='
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '0'
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ! '>='
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
version: '0'
|
59
|
+
requirements: []
|
60
|
+
rubyforge_project:
|
61
|
+
rubygems_version: 1.8.24
|
62
|
+
signing_key:
|
63
|
+
specification_version: 3
|
64
|
+
summary: Approval Hub API
|
65
|
+
test_files: []
|