nakamura 0.1

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/lib/nakamura.rb ADDED
@@ -0,0 +1,412 @@
1
+ #!/usr/bin/env ruby
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'cgi'
5
+ require 'rubygems'
6
+ require 'json'
7
+ require 'yaml'
8
+ require 'nakamura/users'
9
+ require 'logger'
10
+
11
+ class String
12
+ def base64_decode
13
+ unpack('m').first
14
+ end
15
+
16
+ def base64_encode
17
+ [self].pack('m').chop
18
+ end
19
+ end
20
+
21
+
22
+ class Hash
23
+
24
+ def dump
25
+ return keys.collect{|k| "#{k} => #{self[k]}"}.join(", ")
26
+ end
27
+
28
+ end
29
+
30
+ ## Fix array handling
31
+ module Net::HTTPHeader
32
+ def set_form_data(params, sep = '&')
33
+ self.body = params.map {|k, v| encode_kvpair(k, v) }.flatten.join(sep)
34
+ self.content_type = 'application/x-www-form-urlencoded'
35
+ end
36
+
37
+
38
+ def initialize_http_header(initheader)
39
+ @header = { "Referer" => ["/dev/integrationtests"] }
40
+ return unless initheader
41
+ initheader.each do |key, value|
42
+ warn "net/http: warning: duplicated HTTP header: #{key}" if key?(key) and $VERBOSE
43
+ @header[key.downcase] = [value.strip]
44
+ end
45
+ end
46
+
47
+ def encode_kvpair(k, vs)
48
+ if vs.nil? or vs == '' then
49
+ "#{urlencode(k)}="
50
+ else
51
+ Array(vs).map {|v| "#{urlencode(k)}=#{urlencode(v.to_s)}" }
52
+ end
53
+ end
54
+ end
55
+
56
+ class WrappedCurlResponse
57
+
58
+ def initialize(response)
59
+ @response = response
60
+ end
61
+
62
+ def code
63
+ return @response.response_code
64
+ end
65
+
66
+ def message
67
+ return @response.response_code
68
+ end
69
+
70
+ def body
71
+ return @response.body_str
72
+ end
73
+
74
+ end
75
+
76
+ module SlingInterface
77
+
78
+ class Sling
79
+
80
+ attr_accessor :log, :trustedauth
81
+
82
+ def initialize(server="http://localhost:8080/", trustedauth=false)
83
+ @server = server
84
+ @serveruri = URI.parse(server)
85
+ @user = SlingUsers::User.admin_user()
86
+ @trustedauth = trustedauth
87
+ @cookies = Hash.new()
88
+ @loggedin = false
89
+ @log = Logger.new(STDOUT)
90
+ @log.level = Logger::WARN
91
+ end
92
+
93
+ def dump_response(response)
94
+ @log.info "Response: #{response.code} #{response.message}"
95
+ @log.debug "#{response.body}"
96
+ end
97
+
98
+ def switch_user(user)
99
+ @log.info "Switched user to #{user}"
100
+ @cookies = Hash.new()
101
+ @user = user
102
+ if ( @trustedauth )
103
+ @loggedin = false
104
+ end
105
+ end
106
+
107
+
108
+ def text_to_multipart(key,value)
109
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n" +
110
+ "\r\n" +
111
+ "#{value}\r\n"
112
+ end
113
+
114
+ def file_to_multipart(key,filename,mime_type,content)
115
+ if ( filename != nil )
116
+ return "Content-Disposition: form-data; name=\"*\"; filename=\"#{filename}\"\r\n" +
117
+ "Content-Transfer-Encoding: binary\r\n" +
118
+ "Content-Type: #{mime_type}\r\n" +
119
+ "\r\n" +
120
+ "#{content}\r\n"
121
+ else
122
+ return "Content-Disposition: form-data; name=\"jcr:content\"\r\n" +
123
+ "Content-Transfer-Encoding: binary\r\n" +
124
+ "Content-Type: #{mime_type}\r\n" +
125
+ "\r\n" +
126
+ "#{content}\r\n"
127
+ end
128
+
129
+ end
130
+
131
+ def execute_file_post(path, fieldname, filename, data, content_type)
132
+ uri = URI.parse(path)
133
+ fileTypeHint = "Content-Disposition: form-data; name=\"*@TypeHint\"\r\n\r\n" +
134
+ "nt:file\r\n"
135
+
136
+ params = [fileTypeHint,file_to_multipart(fieldname, filename, content_type, data)]
137
+ boundary = '349832898984244898448024464570528145'
138
+ post_body = params.collect {|p| '--' + boundary + "\r\n" + p}.join('') + "--" + boundary + "--\r\n"
139
+ req = Net::HTTP::Post.new(uri.path)
140
+ req.set_content_type("multipart/form-data", {"boundary" => boundary})
141
+ req.body = post_body
142
+ res = sendRequest(uri, req)
143
+ dump_response(res)
144
+ return res
145
+ end
146
+
147
+ def createHttp(uri)
148
+ http = Net::HTTP.new(uri.host, uri.port)
149
+ if (uri.scheme == 'https')
150
+ http.use_ssl = true
151
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
152
+ end
153
+ return http
154
+ end
155
+
156
+ def sendRequest(uri, req)
157
+ # Not all browsers take port number into account when setting cookies.
158
+ isSlingReq = uri.host && (uri.host == @serveruri.host)
159
+ if (isSlingReq)
160
+ if ( @trustedauth )
161
+ if ( ! @loggedin )
162
+ do_login()
163
+ end
164
+ else
165
+ @user.do_request_auth(req)
166
+ end
167
+ set_cookies(req)
168
+ else
169
+ @log.warn("Path #{uri} is not a Sling URL, not sending state")
170
+ end
171
+ res = createHttp(uri).start { |http| http.request(req ) }
172
+ save_cookies(res) if (isSlingReq)
173
+ return res
174
+ end
175
+
176
+ def delete_file(path)
177
+ uri = URI.parse(path)
178
+ req = Net::HTTP::Delete.new(uri.path)
179
+ res = sendRequest(uri, req)
180
+ dump_response(res)
181
+ return res
182
+ end
183
+
184
+ def execute_put_file(path, data)
185
+ @log.debug "URL: #{path}"
186
+ @log.debug("PUTFILE: #{path} (as '#{@user.name}')")
187
+ uri = URI.parse(path)
188
+ req = Net::HTTP::Put.new(uri.path)
189
+ req.body = data
190
+ res = sendRequest(uri, req)
191
+ dump_response(res)
192
+ return res
193
+ end
194
+
195
+ def execute_post(path, post_params={})
196
+ # We always post with utf-8
197
+ if ( post_params["_charset_"] == nil)
198
+ post_params["_charset_"] = "utf-8"
199
+ end
200
+ @log.debug("POST: #{path} (as '#{@user.name}')\n\tparams: #{post_params.dump}")
201
+ uri = URI.parse(path)
202
+ req = Net::HTTP::Post.new(uri.path)
203
+ req.set_form_data(post_params)
204
+ res = sendRequest(uri, req)
205
+ dump_response(res)
206
+ return res
207
+ end
208
+
209
+ def execute_get(path, query_params=nil)
210
+ if (query_params != nil)
211
+ param_string = query_params.collect { |k,v|
212
+ val = case v
213
+ when String then
214
+ v
215
+ when Numeric then
216
+ v.to_s
217
+ else
218
+ v.to_json
219
+ end
220
+ CGI.escape(k) + "=" + CGI.escape(val)
221
+ }.join("&")
222
+ path = "#{path}?#{param_string}"
223
+ end
224
+ @log.debug "URL: #{path}"
225
+ uri = URI.parse(path)
226
+ path = uri.path
227
+ path = path + "?" + uri.query if uri.query
228
+ @log.debug("GET: #{path} (as '#{@user.name}')")
229
+ req = Net::HTTP::Get.new(path)
230
+ res = sendRequest(uri, req)
231
+ res = followRedirects(res)
232
+ dump_response(res)
233
+ return res
234
+ end
235
+
236
+ def followRedirects(res)
237
+ lastlocation = ''
238
+ while (res.header['location'] && res.header['location'] != lastlocation)
239
+ lastlocation = res.header['location']
240
+ uri = URI.parse(res.header['location'])
241
+ @log.info("Redirecting to #{uri}")
242
+ req = Net::HTTP::Get.new(uri.request_uri())
243
+ res = sendRequest(uri, req)
244
+ end
245
+ return res
246
+ end
247
+
248
+ def set_cookies(req)
249
+ req["Cookie"] = @cookies.values * ", "
250
+ @log.debug("Cookie is #{req["Cookie"]}")
251
+ end
252
+
253
+ def save_cookies(res)
254
+ if ( res["Set-Cookie"] )
255
+ setcookie = res.get_fields('Set-Cookie')
256
+ @log.debug("Set-Cookie header #{setcookie} ")
257
+ setcookie.each do |cookieitem|
258
+ cookie = cookieitem.split(/;/)[0]
259
+ cookiename = cookie.split(/=/)[0]
260
+ value = cookie.split(/=/)[1]
261
+ cookievalue = "#{cookiename}=#{value}"
262
+ if ( @cookies[cookiename] != cookievalue )
263
+ @cookies[cookiename] = cookievalue
264
+ @log.info("New Cookie Value #{@cookies.values * "' "} ")
265
+ else
266
+ @log.debug("No Change to Cookie #{@cookies}")
267
+ end
268
+ end
269
+ end
270
+ end
271
+
272
+ def do_login()
273
+ path = url_for("/system/sling/formlogin")
274
+ req = Net::HTTP::Post.new(path)
275
+ uri = URI.parse(path)
276
+ req.set_form_data({ "sakaiauth:un" => @user.name, "sakaiauth:pw" => @user.password, "sakaiauth:login" => 1 })
277
+ res = createHttp(uri).start{ |http| http.request(req) }
278
+ if ( res.code == "200" )
279
+ save_cookies(res)
280
+ @log.info("Login Ok, cookie was {#@cookies}")
281
+ @loggedin = true
282
+ else
283
+ @log.info("Failed to perform login, got "+res.code+" response code")
284
+ end
285
+ end
286
+
287
+ def url_for(path)
288
+ if (path.slice(0,1) == '/')
289
+ path = path[1..-1]
290
+ end
291
+ return "#{@server}#{path}"
292
+ end
293
+
294
+ def update_properties(principal, props)
295
+ principal.update_properties(self, props)
296
+ end
297
+
298
+ def delete_node(path)
299
+ result = execute_post(url_for(path), ":operation" => "delete")
300
+ end
301
+
302
+ def create_file_node(path, fieldname, filename, data, content_type="text/plain")
303
+ result = execute_file_post(url_for(path), fieldname, filename, data, content_type)
304
+ end
305
+
306
+ def create_node(path, params)
307
+ result = execute_post(url_for(path), params)
308
+ end
309
+
310
+ def get_user()
311
+ return @user
312
+ end
313
+
314
+ def get_node_props_json(path)
315
+ @log.debug "Getting props for path: #{path}"
316
+ result = execute_get(url_for("#{path}.json"))
317
+ if ( result.code == "200" )
318
+ return result.body
319
+ end
320
+ @log.info("Failed to get properties for "+path+" cause "+result.code+"\n"+result.body)
321
+ return "{}"
322
+ end
323
+
324
+ def get_node_props(path)
325
+ return JSON.parse(get_node_props_json(path))
326
+ end
327
+
328
+ def update_node_props(path, props)
329
+ return execute_post(url_for(path), props)
330
+ end
331
+
332
+ def get_node_acl_json(path)
333
+ return execute_get(url_for("#{path}.acl.json")).body
334
+ end
335
+
336
+ def get_node_ruleacl_json(path)
337
+ return execute_get(url_for("#{path}.ruleacl.json")).body
338
+ end
339
+
340
+ def get_node_acl(path)
341
+ return JSON.parse(get_node_acl_json(path))
342
+ end
343
+
344
+ def get_node_ruleacl(path)
345
+ return JSON.parse(get_node_ruleacl_json(path))
346
+ end
347
+
348
+ def set_node_acl_entries(path, principal, privs)
349
+ @log.info "Setting node acl for: #{principal} to #{privs.dump}"
350
+ res = execute_post(url_for("#{path}.modifyAce.html"),
351
+ { "principalId" => principal.name }.update(
352
+ privs.keys.inject(Hash.new) do |n,k|
353
+ n.update("privilege@#{k}" => privs[k])
354
+ end))
355
+ return res
356
+ end
357
+
358
+ def set_node_acl_rule_entries(path, principal, privs, props)
359
+ @log.info "Setting node acl for: #{principal} to #{privs.dump}"
360
+ props["principalId"] = principal.name
361
+ res = execute_post(url_for("#{path}.modifyRuleAce.html"),
362
+ props.update(
363
+ privs.keys.inject(Hash.new) do |n,k|
364
+ n.update("privilege@#{k}" => privs[k])
365
+ end))
366
+ return res
367
+ end
368
+
369
+ def delete_node_acl_entries(path, principal)
370
+ res = execute_post(url_for("#{path}.deleteAce.html"), {
371
+ ":applyTo" => principal
372
+ })
373
+ end
374
+
375
+ def clear_acl(path)
376
+ acl = JSON.parse(get_node_acl_json(path))
377
+ acl.keys.each { |p| delete_node_acl_entries(path, p) }
378
+ end
379
+
380
+ def save_node(path)
381
+ res = execute_post(url_for("#{path}.save.json"), {})
382
+ if (res.code == "200")
383
+ return JSON.parse(res.body)["versionName"]
384
+ end
385
+ return nil
386
+ end
387
+
388
+ def versions(path)
389
+ return get_node_props("#{path}.versions")["versions"].keys
390
+ end
391
+
392
+ def version(path, version, extension)
393
+ return execute_get(url_for("#{path}.version.,#{version},.#{extension}"))
394
+ end
395
+
396
+ end
397
+
398
+ end
399
+
400
+ if __FILE__ == $0
401
+ @log.info "Sling test"
402
+ s = SlingInterface::Sling.new("http://localhost:8080/", false)
403
+ um = SlingUsers::UserManager.new(s)
404
+ um.create_group(10)
405
+ user = um.create_test_user(10)
406
+ s.create_node("fish", { "foo" => "bar", "baz" => "jim" })
407
+ @log.info s.get_node_props_json("fish")
408
+ @log.info s.get_node_acl_json("fish")
409
+
410
+ s.set_node_acl_entries("fish", user, { "jcr:write" => "granted" })
411
+ @log.info s.get_node_acl_json("fish")
412
+ end
metadata ADDED
@@ -0,0 +1,55 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nakamura
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Sakai Project
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-09-30 00:00:00.000000000Z
13
+ dependencies: []
14
+ description: Ruby library for interacting with Sakai Nakamura. Provides convenience
15
+ methods for adding users and groups and other similar tasks.
16
+ email: oae-dev@collab.sakaiproject.org
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - lib/nakamura/test.rb
22
+ - lib/nakamura/authz.rb
23
+ - lib/nakamura/full_group_creator.rb
24
+ - lib/nakamura/users.rb
25
+ - lib/nakamura/contacts.rb
26
+ - lib/nakamura/message.rb
27
+ - lib/nakamura/search.rb
28
+ - lib/nakamura/file.rb
29
+ - lib/nakamura.rb
30
+ homepage: http://sakaiproject.org
31
+ licenses: []
32
+ post_install_message:
33
+ rdoc_options: []
34
+ require_paths:
35
+ - lib
36
+ required_ruby_version: !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ required_rubygems_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ requirements:
49
+ - none
50
+ rubyforge_project:
51
+ rubygems_version: 1.8.6
52
+ signing_key:
53
+ specification_version: 3
54
+ summary: Ruby library for interacting with Sakai Nakamura.
55
+ test_files: []