granicus-platform-api 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/Changelog +0 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +48 -0
- data/LICENSE +0 -0
- data/README.rdoc +59 -0
- data/granicus-platform-api.gemspec +30 -0
- data/lib/granicus-platform-api/client.rb +291 -0
- data/lib/granicus-platform-api/granicus-platform-api.xml +1824 -0
- data/lib/granicus-platform-api/version.rb +3 -0
- data/lib/granicus-platform-api.rb +6 -0
- data/spec/granicus-platform-api_spec.rb +154 -0
- data/spec/helper.rb +14 -0
- metadata +137 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Changelog
ADDED
File without changes
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
granicus-platform-api (0.1.0)
|
5
|
+
hashie (~> 1.0.0)
|
6
|
+
multi_xml (~> 0.2.2)
|
7
|
+
savon (~> 0.9.2)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
builder (2.1.2)
|
13
|
+
diff-lcs (1.1.2)
|
14
|
+
gyoku (0.4.4)
|
15
|
+
builder (>= 2.1.2)
|
16
|
+
hashie (1.0.0)
|
17
|
+
httpi (0.9.4)
|
18
|
+
pyu-ntlm-http (>= 0.1.3.1)
|
19
|
+
rack
|
20
|
+
multi_xml (0.2.2)
|
21
|
+
nokogiri (1.4.4)
|
22
|
+
nori (1.0.1)
|
23
|
+
pyu-ntlm-http (0.1.3.1)
|
24
|
+
rack (1.3.0)
|
25
|
+
rspec (2.6.0)
|
26
|
+
rspec-core (~> 2.6.0)
|
27
|
+
rspec-expectations (~> 2.6.0)
|
28
|
+
rspec-mocks (~> 2.6.0)
|
29
|
+
rspec-core (2.6.4)
|
30
|
+
rspec-expectations (2.6.0)
|
31
|
+
diff-lcs (~> 1.1.2)
|
32
|
+
rspec-mocks (2.6.0)
|
33
|
+
savon (0.9.2)
|
34
|
+
builder (>= 2.1.2)
|
35
|
+
gyoku (>= 0.4.0)
|
36
|
+
httpi (>= 0.7.8)
|
37
|
+
nokogiri (>= 1.4.0)
|
38
|
+
nori (>= 0.2.0)
|
39
|
+
|
40
|
+
PLATFORMS
|
41
|
+
ruby
|
42
|
+
|
43
|
+
DEPENDENCIES
|
44
|
+
granicus-platform-api!
|
45
|
+
hashie (~> 1.0.0)
|
46
|
+
multi_xml (~> 0.2.2)
|
47
|
+
rspec (~> 2.6)
|
48
|
+
savon (~> 0.9.2)
|
data/LICENSE
ADDED
File without changes
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= Overview
|
2
|
+
|
3
|
+
== About Granicus Platform API
|
4
|
+
|
5
|
+
Granicus is a platform for government transparency and citizen engagement in use by over 900 government organizations, from small towns to the US Congress. This Ruby wrapper allows for integration with the SOAP web service that can be used to automate backend tasks in the system.
|
6
|
+
|
7
|
+
== WARNING
|
8
|
+
|
9
|
+
This gem is still under heavy development, and is not recommended for production use. Contributions and suggestions are welcome.
|
10
|
+
|
11
|
+
== Usage
|
12
|
+
|
13
|
+
First:
|
14
|
+
|
15
|
+
<tt>gem install granicus-platform-api</tt>
|
16
|
+
|
17
|
+
Then create a client:
|
18
|
+
|
19
|
+
<tt>granicus = GranicusPlatformAPI::Client.new(<customer site>,<username>,<password>)</tt>
|
20
|
+
|
21
|
+
Granicus site is, for instance, sanfrancisco.granicus.com. Username and password must be a valid username/password for the site. This API is not for public access. If you wish to gain access to an API for public access, join the Granicus Developers Google Group.
|
22
|
+
|
23
|
+
Once you have initialized your client, you can make calls to the documented API methods. The only difference is that you will use snake_case methods and properties rather than CamelCase ones. For example:
|
24
|
+
|
25
|
+
<tt>clips = granicus.get_clips</tt>
|
26
|
+
|
27
|
+
== Compatibility
|
28
|
+
|
29
|
+
This wrapper is developed against 1.9.2.
|
30
|
+
|
31
|
+
= License
|
32
|
+
|
33
|
+
Copyright (c) 2011 Javier Muniz
|
34
|
+
|
35
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
36
|
+
a copy of this software and associated documentation files (the
|
37
|
+
"Software"), to deal in the Software without restriction, including
|
38
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
39
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
40
|
+
permit persons to whom the Software is furnished to do so, subject to
|
41
|
+
the following conditions:
|
42
|
+
|
43
|
+
The above copyright notice and this permission notice shall be
|
44
|
+
included in all copies or substantial portions of the Software.
|
45
|
+
|
46
|
+
You will notify the author and give permission to have your software
|
47
|
+
listed on this and other websites of the author as using the Software.
|
48
|
+
|
49
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
50
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
51
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
52
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
53
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
54
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
55
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
56
|
+
|
57
|
+
= Credits
|
58
|
+
|
59
|
+
Javier Muniz
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "granicus-platform-api/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "granicus-platform-api"
|
7
|
+
s.version = GranicusPlatformAPI::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Javier Muniz"]
|
10
|
+
s.email = "javier@granicus.com"
|
11
|
+
s.summary = "Granicus Open Platform API 1.x Wrapper"
|
12
|
+
s.homepage = "http://github.com/gov20cto/granicus-platform-api"
|
13
|
+
s.description = "Wrapper for the Granicus Open Platform API v1.x"
|
14
|
+
|
15
|
+
s.rubyforge_project = "granicus-platform-api"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_development_dependency('rspec', '~> 2.6')
|
23
|
+
s.add_development_dependency('hashie', '~> 1.0.0')
|
24
|
+
s.add_development_dependency('savon', '~> 0.9.2')
|
25
|
+
s.add_development_dependency('multi_xml', '~> 0.2.2')
|
26
|
+
|
27
|
+
s.add_dependency('savon', '~> 0.9.2')
|
28
|
+
s.add_dependency('hashie', '~> 1.0.0')
|
29
|
+
s.add_dependency('multi_xml', '~> 0.2.2')
|
30
|
+
end
|
@@ -0,0 +1,291 @@
|
|
1
|
+
require 'savon'
|
2
|
+
require 'hashie'
|
3
|
+
require 'multi_xml'
|
4
|
+
|
5
|
+
module GranicusPlatformAPI
|
6
|
+
class Client
|
7
|
+
|
8
|
+
# create a connected client
|
9
|
+
def initialize(granicus_site,username,password,options={})
|
10
|
+
# set things up
|
11
|
+
@granicus_site = granicus_site
|
12
|
+
Savon.configure do |config|
|
13
|
+
config.log = false
|
14
|
+
end
|
15
|
+
HTTPI.log = false
|
16
|
+
|
17
|
+
# create the client
|
18
|
+
@client = Savon::Client.new do |wsdl, http|
|
19
|
+
wsdl.document = File.expand_path("../granicus-platform-api.xml", __FILE__)
|
20
|
+
wsdl.endpoint = "http://#{granicus_site}/SDK/User/index.php"
|
21
|
+
http.proxy = "http://localhost:8888"
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
# call login
|
26
|
+
@client.request :wsdl, :login do
|
27
|
+
soap.body = { :username => username, :password => password }
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
# return the current logged on user name
|
33
|
+
def get_current_user_logon
|
34
|
+
response = @client.request :wsdl, :get_current_user_logon
|
35
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
36
|
+
config.noblanks
|
37
|
+
end
|
38
|
+
typecast_value_node doc.xpath('//ns4:GetCurrentUserLogonResponse/Logon', doc.root.namespaces)[0]
|
39
|
+
end
|
40
|
+
|
41
|
+
# logout
|
42
|
+
def logout
|
43
|
+
response = @client.request :wsdl, :logout
|
44
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
45
|
+
config.noblanks
|
46
|
+
end
|
47
|
+
typecast_value_node doc.xpath('//ns4:LogoutResponse', doc.root.namespaces)[0]
|
48
|
+
end
|
49
|
+
|
50
|
+
# return all of the cameras
|
51
|
+
def get_cameras
|
52
|
+
response = @client.request :wsdl, :get_cameras
|
53
|
+
|
54
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
55
|
+
config.noblanks
|
56
|
+
end
|
57
|
+
typecast_value_node doc.xpath('//ns5:GetCamerasResponse/cameras', doc.root.namespaces)[0]
|
58
|
+
end
|
59
|
+
|
60
|
+
# return the requested event
|
61
|
+
def get_camera(camera_id)
|
62
|
+
response = @client.request :wsdl, :get_camera do
|
63
|
+
soap.body = { :camera_id => camera_id, :attributes! => {:camera_id => {"xsi:type" => "xsd:int"}} }
|
64
|
+
end
|
65
|
+
|
66
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
67
|
+
config.noblanks
|
68
|
+
end
|
69
|
+
typecast_value_node doc.xpath('//ns5:GetCameraResponse/camera', doc.root.namespaces)[0]
|
70
|
+
end
|
71
|
+
|
72
|
+
# return all of the events
|
73
|
+
def get_events
|
74
|
+
response = @client.request :wsdl, :get_events
|
75
|
+
|
76
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
77
|
+
config.noblanks
|
78
|
+
end
|
79
|
+
typecast_value_node doc.xpath('//ns5:GetEventsResponse/events', doc.root.namespaces)[0]
|
80
|
+
end
|
81
|
+
|
82
|
+
# return all of the events with matching foreign id
|
83
|
+
def get_events_by_foreign_id(foreign_id)
|
84
|
+
response = @client.request :wsdl, :get_events_by_foreign_id do
|
85
|
+
soap.body = { :foreign_id => foreign_id, :attributes! => {:foreign_id => {"xsi:type" => "xsd:int"}} }
|
86
|
+
end
|
87
|
+
|
88
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
89
|
+
config.noblanks
|
90
|
+
end
|
91
|
+
typecast_value_node doc.xpath('//ns5:GetEventsByForeignIDResponse/events', doc.root.namespaces)[0]
|
92
|
+
end
|
93
|
+
|
94
|
+
# return the requested event
|
95
|
+
def get_event(event_id)
|
96
|
+
response = @client.request :wsdl, :get_event do
|
97
|
+
soap.body = { :event_id => event_id, :attributes! => {:event_id => {"xsi:type" => "xsd:int"}} }
|
98
|
+
end
|
99
|
+
|
100
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
101
|
+
config.noblanks
|
102
|
+
end
|
103
|
+
typecast_value_node doc.xpath('//ns5:GetEventResponse/event', doc.root.namespaces)[0]
|
104
|
+
end
|
105
|
+
|
106
|
+
# return all of the event meta data
|
107
|
+
def get_event_meta_data(event_id)
|
108
|
+
response = @client.request :wsdl, :get_event_meta_data do
|
109
|
+
soap.body = { :event_id => event_id, :attributes! => {:event_id => {"xsi:type" => "xsd:int"}} }
|
110
|
+
end
|
111
|
+
|
112
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
113
|
+
config.noblanks
|
114
|
+
end
|
115
|
+
typecast_value_node doc.xpath('//ns5:GetEventMetaDataResponse/metadata', doc.root.namespaces)[0]
|
116
|
+
end
|
117
|
+
|
118
|
+
# set the event agenda url
|
119
|
+
def set_event_agenda_url(event_id,url)
|
120
|
+
response = @client.request :wsdl, :set_event_agenda_url do
|
121
|
+
soap.body = { :event_id => event_id,
|
122
|
+
:url => url,
|
123
|
+
:attributes! => {:event_id => {"xsi:type" => "xsd:int"}, :url => {"xsi:type" => "xsd:string"}} }
|
124
|
+
end
|
125
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
126
|
+
config.noblanks
|
127
|
+
end
|
128
|
+
typecast_value_node doc.xpath('//ns4:SetEventAgendaURLResponse', doc.root.namespaces)[0]
|
129
|
+
end
|
130
|
+
|
131
|
+
# return all of the clip meta data
|
132
|
+
def get_clip_meta_data(clip_id)
|
133
|
+
response = @client.request :wsdl, :get_clip_meta_data do
|
134
|
+
soap.body = { :clip_id => clip_id, :attributes! => {:clip_id => {"xsi:type" => "xsd:int"}} }
|
135
|
+
end
|
136
|
+
|
137
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
138
|
+
config.noblanks
|
139
|
+
end
|
140
|
+
typecast_value_node doc.xpath('//ns5:GetClipMetaDataResponse/metadata', doc.root.namespaces)[0]
|
141
|
+
end
|
142
|
+
|
143
|
+
# return all of the folders
|
144
|
+
def get_folders
|
145
|
+
response = @client.request :wsdl, :get_folders
|
146
|
+
|
147
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
148
|
+
config.noblanks
|
149
|
+
end
|
150
|
+
typecast_value_node doc.xpath('//ns5:GetFoldersResponse/folders', doc.root.namespaces)[0]
|
151
|
+
end
|
152
|
+
|
153
|
+
# return all of the clips
|
154
|
+
def get_clips(folder_id)
|
155
|
+
response = @client.request :wsdl, :get_clips do
|
156
|
+
soap.body = { :folder_id => folder_id, :attributes! => {:folder_id => {"xsi:type" => "xsd:int"}} }
|
157
|
+
end
|
158
|
+
|
159
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
160
|
+
config.noblanks
|
161
|
+
end
|
162
|
+
typecast_value_node doc.xpath('//ns5:GetClipsResponse/clips', doc.root.namespaces)[0]
|
163
|
+
end
|
164
|
+
|
165
|
+
# return all of the clips with matching foreign id
|
166
|
+
def get_clips_by_foreign_id(foreign_id)
|
167
|
+
response = @client.request :wsdl, :get_clips_by_foreign_id do
|
168
|
+
soap.body = { :foreign_id => foreign_id, :attributes! => {:foreign_id => {"xsi:type" => "xsd:int"}} }
|
169
|
+
end
|
170
|
+
|
171
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
172
|
+
config.noblanks
|
173
|
+
end
|
174
|
+
typecast_value_node doc.xpath('//ns5:GetClipsByForeignIDResponse/clips', doc.root.namespaces)[0]
|
175
|
+
end
|
176
|
+
|
177
|
+
# return the requested clip
|
178
|
+
def get_clip(clip_id)
|
179
|
+
response = @client.request :wsdl, :get_clip do
|
180
|
+
soap.body = { :clip_id => clip_id, :attributes! => {:clip_id => {"xsi:type" => "xsd:int"}} }
|
181
|
+
end
|
182
|
+
|
183
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
184
|
+
config.noblanks
|
185
|
+
end
|
186
|
+
typecast_value_node doc.xpath('//ns5:GetClipResponse/clip', doc.root.namespaces)[0]
|
187
|
+
end
|
188
|
+
|
189
|
+
# return the requested clip
|
190
|
+
def get_clip_by_uid(clip_uid)
|
191
|
+
response = @client.request :wsdl, :get_clip_by_uid do
|
192
|
+
soap.body = { :clip_uid => clip_uid, :attributes! => {:clip_uid => {"xsi:type" => "xsd:string"}} }
|
193
|
+
end
|
194
|
+
|
195
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
196
|
+
config.noblanks
|
197
|
+
end
|
198
|
+
typecast_value_node doc.xpath('//ns5:GetClipByUIDResponse/clip', doc.root.namespaces)[0]
|
199
|
+
end
|
200
|
+
|
201
|
+
# get servers
|
202
|
+
def get_servers
|
203
|
+
response = @client.request :wsdl, :get_servers
|
204
|
+
|
205
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
206
|
+
config.noblanks
|
207
|
+
end
|
208
|
+
typecast_value_node doc.xpath('//ns5:GetServersResponse/servers', doc.root.namespaces)[0]
|
209
|
+
end
|
210
|
+
|
211
|
+
# return the requested server
|
212
|
+
def get_server(server_id)
|
213
|
+
response = @client.request :wsdl, :get_server do
|
214
|
+
soap.body = { :server_id => server_id, :attributes! => {:server_id => {"xsi:type" => "xsd:int"}} }
|
215
|
+
end
|
216
|
+
|
217
|
+
doc = Nokogiri::XML(response.to_xml) do |config|
|
218
|
+
config.noblanks
|
219
|
+
end
|
220
|
+
typecast_value_node doc.xpath('//ns5:GetServerResponse/server', doc.root.namespaces)[0]
|
221
|
+
end
|
222
|
+
|
223
|
+
private
|
224
|
+
|
225
|
+
def typecast_value_node(node)
|
226
|
+
if node.is_a? Nokogiri::XML::NodeSet or node.is_a? Array then
|
227
|
+
return node.map {|el| typecast_value_node el }
|
228
|
+
end
|
229
|
+
return node.to_s unless node['type']
|
230
|
+
typespace,type = node['type'].split(':')
|
231
|
+
case typespace
|
232
|
+
when 'xsd'
|
233
|
+
proc = self.class.typecasts[type]
|
234
|
+
unless proc.nil?
|
235
|
+
proc.call(node.children[0].to_s)
|
236
|
+
else
|
237
|
+
puts "Unknown xsd:type: #{type}"
|
238
|
+
node.children[0].to_s
|
239
|
+
end
|
240
|
+
when 'SOAP-ENC'
|
241
|
+
if type == 'Array' then
|
242
|
+
node.children.map {|element| typecast_value_node element }
|
243
|
+
else
|
244
|
+
puts "Unknown SOAP-ENC:type: #{type}"
|
245
|
+
node.to_s
|
246
|
+
end
|
247
|
+
else
|
248
|
+
# we have a custom type, make it hashie since we don't want true static typing
|
249
|
+
value = ::Hashie::Mash.new
|
250
|
+
node.children.each do |value_node|
|
251
|
+
value[value_node.name.snakecase] = typecast_value_node value_node
|
252
|
+
end
|
253
|
+
value
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
# typecasts ripped from rubiii/nori, adapted for xsd types
|
258
|
+
def self.typecasts
|
259
|
+
@@typecasts
|
260
|
+
end
|
261
|
+
|
262
|
+
def self.typecasts=(obj)
|
263
|
+
@@typecasts = obj
|
264
|
+
end
|
265
|
+
|
266
|
+
def self.available_typecasts
|
267
|
+
@@available_typecasts
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.available_typecasts=(obj)
|
271
|
+
@@available_typecasts = obj
|
272
|
+
end
|
273
|
+
|
274
|
+
self.typecasts = {}
|
275
|
+
self.typecasts["int"] = lambda { |v| v.nil? ? nil : v.to_i }
|
276
|
+
self.typecasts["boolean"] = lambda { |v| v.nil? ? nil : (v.strip != "false") }
|
277
|
+
self.typecasts["datetime"] = lambda { |v| v.nil? ? nil : Time.parse(v).utc }
|
278
|
+
self.typecasts["date"] = lambda { |v| v.nil? ? nil : Date.parse(v) }
|
279
|
+
self.typecasts["dateTime"] = lambda { |v| v.nil? ? nil : Time.parse(v).utc }
|
280
|
+
self.typecasts["decimal"] = lambda { |v| v.nil? ? nil : BigDecimal(v.to_s) }
|
281
|
+
self.typecasts["double"] = lambda { |v| v.nil? ? nil : v.to_f }
|
282
|
+
self.typecasts["float"] = lambda { |v| v.nil? ? nil : v.to_f }
|
283
|
+
self.typecasts["symbol"] = lambda { |v| v.nil? ? nil : v.to_sym }
|
284
|
+
self.typecasts["string"] = lambda { |v| v.to_s }
|
285
|
+
self.typecasts["yaml"] = lambda { |v| v.nil? ? nil : YAML.load(v) }
|
286
|
+
self.typecasts["base64Binary"] = lambda { |v| v.unpack('m').first }
|
287
|
+
|
288
|
+
self.available_typecasts = self.typecasts.keys
|
289
|
+
|
290
|
+
end
|
291
|
+
end
|