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 ADDED
@@ -0,0 +1,2 @@
1
+ coverage
2
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/Changelog ADDED
File without changes
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in gem_template.gemspec
4
+ gemspec
5
+
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