zenbe-flareshow 0.2.4 → 0.3.0

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.
@@ -5,12 +5,12 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{flareshow}
8
- s.version = "0.2.4"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Will Bailey"]
12
- s.date = %q{2009-09-11}
13
- s.description = %q{TODO: a ruby gem for interacting with the shareflow collaboration service by Zenbe}
12
+ s.date = %q{2009-09-12}
13
+ s.description = %q{a ruby gem for interacting with the shareflow collaboration service by Zenbe}
14
14
  s.email = %q{will.bailey@gmail.com}
15
15
  s.extra_rdoc_files = [
16
16
  "LICENSE",
@@ -30,8 +30,10 @@ Gem::Specification.new do |s|
30
30
  "lib/file_attachment.rb",
31
31
  "lib/flareshow.rb",
32
32
  "lib/flow.rb",
33
+ "lib/http_encoding_helper.rb",
33
34
  "lib/invitation.rb",
34
35
  "lib/membership.rb",
36
+ "lib/mime_parts.rb",
35
37
  "lib/post.rb",
36
38
  "lib/resource.rb",
37
39
  "lib/searchable.rb",
@@ -46,8 +48,8 @@ Gem::Specification.new do |s|
46
48
  s.rdoc_options = ["--charset=UTF-8"]
47
49
  s.require_paths = ["lib"]
48
50
  s.rubyforge_project = %q{flareshow}
49
- s.rubygems_version = %q{1.3.5}
50
- s.summary = %q{TODO: a ruby gem for interacting with the shareflow collaboration service}
51
+ s.rubygems_version = %q{1.3.4}
52
+ s.summary = %q{a ruby gem for interacting with the shareflow collaboration service}
51
53
  s.test_files = [
52
54
  "test/flareshow_test.rb",
53
55
  "test/test_helper.rb"
data/README.md CHANGED
@@ -91,7 +91,7 @@ Flareshow offers an ActiveRecord like syntax for retrieving and manipulating mod
91
91
  f.name = 'a different name'
92
92
  f.save
93
93
 
94
- ### Inviting someone to a flow (only available if you are the creator of the flow)
94
+ #### inviting someone to a flow (only available if you are the creator of the flow)
95
95
 
96
96
  f=Flow.find_by_name('test')
97
97
  f.send_invitations('test@test.com')
@@ -99,21 +99,21 @@ Flareshow offers an ActiveRecord like syntax for retrieving and manipulating mod
99
99
  # this also works
100
100
  f.send_invitations(['test1@test.com', 'test2@test.com'])
101
101
 
102
- ### Canceling an invitation to a flow (only available if you are the creator of the flow)
102
+ #### canceling an invitation to a flow (only available if you are the creator of the flow)
103
103
 
104
104
  f=Flow.find_by_name('test')
105
105
  # revoke an invitation by the email address that was invited
106
106
  f.revoke_invitations('test@test.com')
107
107
 
108
108
 
109
- ### Removing a user from a flow (only available if you are the creator of the flow)
109
+ #### removing a user from a flow (only available if you are the creator of the flow)
110
110
 
111
111
  f = Flow.find_by_name('test')
112
112
  users = f.list_users # get a listing of the users on the flow
113
113
  # remove the last user in the list from the flow...you cant remove yourself in this way
114
114
  f.remove_members(users.last.id)
115
115
 
116
- ### listing all the users on a flow
116
+ #### listing all the users on a flow
117
117
 
118
118
  f=Flow.first
119
119
  f.list_users
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.4
1
+ 0.3.0
@@ -3,16 +3,19 @@ ROOT = File.dirname(__FILE__) unless defined? ROOT
3
3
  # gems
4
4
  require 'rubygems' #TODO fix
5
5
  require 'json'
6
- require 'curb'
7
6
  require 'facets'
8
7
  require 'facets/dictionary'
9
8
  require 'uuid'
10
- require 'ruby-debug'
9
+ require 'mime/types'
10
+ require 'cgi'
11
11
 
12
12
  # std lib
13
+ require 'net/http'
14
+ require 'net/https'
13
15
  require 'ostruct'
14
16
  require 'yaml'
15
17
  require 'logger'
18
+ require 'ruby-debug'
16
19
 
17
20
  # Application Constants and configuration
18
21
  module Flareshow
@@ -47,6 +50,7 @@ Dir.glob(File.join(ROOT, "*.rb")).each{|lib| require lib}
47
50
  config_file_path = File.expand_path("~/.flareshowrc")
48
51
  if File.exists?(config_file_path) && !Flareshow::Service.authenticated?
49
52
  data = YAML.load_file(config_file_path)
53
+ Flareshow::Service.debug_output=true if data["debug_http"]
50
54
  host = data["host"] || "biz.zenbe.com"
51
55
  subdomain = data["subdomain"]
52
56
  DEFAULT_LOGGER.level = data["log_level"].to_i if data["log_level"]
@@ -0,0 +1,49 @@
1
+ # Intended to extend the Net::HTTP response object
2
+ # and adds support for decoding gzip and deflate encoded pages
3
+ #
4
+ # Author: Jason Stirk <http://griffin.oobleyboo.com>
5
+ # Home: http://griffin.oobleyboo.com/projects/http_encoding_helper
6
+ # Created: 5 September 2007
7
+ # Last Updated: 23 November 2007
8
+ #
9
+ # Usage:
10
+ #
11
+ # require 'net/http'
12
+ # require 'http_encoding_helper'
13
+ # headers={'Accept-Encoding' => 'gzip, deflate' }
14
+ # http = Net::HTTP.new('griffin.oobleyboo.com', 80)
15
+ # http.start do |h|
16
+ # request = Net::HTTP::Get.new('/', headers)
17
+ # response = http.request(request)
18
+ # content=response.plain_body # Method from our library
19
+ # puts "Transferred: #{response.body.length} bytes"
20
+ # puts "Compression: #{response['content-encoding']}"
21
+ # puts "Extracted: #{response.plain_body.length} bytes"
22
+ # end
23
+ #
24
+
25
+ require 'zlib'
26
+ require 'stringio'
27
+
28
+ class Net::HTTPResponse
29
+ # Return the uncompressed content
30
+ def plain_body
31
+ encoding=self['content-encoding']
32
+ content=nil
33
+ if encoding then
34
+ case encoding
35
+ when 'gzip'
36
+ i=Zlib::GzipReader.new(StringIO.new(self.body))
37
+ content=i.read
38
+ when 'deflate'
39
+ i=Zlib::Inflate.new
40
+ content=i.inflate(self.body)
41
+ else
42
+ raise "Unknown encoding - #{encoding}"
43
+ end
44
+ else
45
+ content=self.body
46
+ end
47
+ return content
48
+ end
49
+ end
@@ -0,0 +1,37 @@
1
+ # Adapted From : http://deftcode.com/code/flickr_upload/multipartpost.rb
2
+
3
+ class Param
4
+ attr_accessor :key, :value, :content_type
5
+ def initialize(key, value, content_type)
6
+ @key = key; @value = value; @content_type = content_type
7
+ end
8
+
9
+ def to_multipart
10
+ return "\r\nContent-Disposition: form-data; name=\"#{CGI::escape(key)}\"\r\n" +
11
+ "Content-Type: #{content_type}; charset=UTF-8" +
12
+ "\r\n\r\n#{value}\r\n"
13
+ end
14
+ end
15
+
16
+ class FileParam
17
+ attr_accessor :key, :filename, :content
18
+ def initialize( key, filename, content )
19
+ @key = key; @filename = filename; @content = content
20
+ end
21
+
22
+ def to_multipart
23
+ return "Content-Disposition: form-data; name=\"#{CGI::escape(key)}\"; filename=\"#{filename}\"\r\n" +
24
+ "Content-Transfer-Encoding: binary\r\n" +
25
+ "Content-type: #{MIME::Types.type_for(filename)}\r\n\r\n" + content + "\r\n"
26
+ end
27
+ end
28
+
29
+ class MultipartPost
30
+ BOUNDARY = "flareshow_multipart_boundary_A0n23hja"
31
+ HEADER = {"Content-type" => "multipart/form-data, boundary=" + BOUNDARY + " "}
32
+
33
+ def self.prepare_query(params)
34
+ query = params.map {|p| "--" + BOUNDARY + "\r\n" + p.to_multipart }.join("") + "--" + BOUNDARY + "--"
35
+ [query, HEADER]
36
+ end
37
+ end
@@ -97,6 +97,7 @@ class Flareshow::Resource
97
97
  self
98
98
  rescue Exception => e
99
99
  Flareshow::Util.log_error e.message
100
+ Flareshow::Util.log_error e.backtrace.join("\n")
100
101
  throw e
101
102
  false
102
103
  end
@@ -5,22 +5,23 @@ class Flareshow::Service
5
5
  # = Class Methods =
6
6
  # =================
7
7
  class << self
8
- attr_accessor :server
8
+ attr_accessor :server, :debug_output, :key
9
9
 
10
10
  # setup the service to use a particular host and domain
11
11
  def configure(subdomain=nil, host='api.zenbe.com')
12
12
  raise Flareshow::ConfigurationException unless subdomain
13
13
  self.server=Server.new(host, subdomain)
14
+ @auth_endpoint = @api_endpoint = nil
14
15
  end
15
16
 
16
17
  # return the authentication endpoint for a given host and domain
17
18
  def auth_endpoint
18
- "http://#{server.host}/#{server.domain}/shareflow/api/v2/auth.json"
19
+ @auth_endpoint ||= URI.parse("http://#{server.host}/#{server.domain}/shareflow/api/v2/auth.json")
19
20
  end
20
21
 
21
22
  # return the api endpoint for a given host and domain
22
23
  def api_endpoint
23
- "http://#{server.host}/#{server.domain}/shareflow/api/v2.json"
24
+ @api_endpoint ||= URI.parse("http://#{server.host}/#{server.domain}/shareflow/api/v2.json")
24
25
  end
25
26
 
26
27
  # has the server been configured?
@@ -33,73 +34,74 @@ class Flareshow::Service
33
34
  # - status code
34
35
  # - headers
35
36
  # - body
36
- def post(url, params)
37
+ def post(uri, params, files=[])
37
38
  raise Flareshow::ConfigurationException unless server_defined?
38
- request = Curl::Easy.new(url) do |curl|
39
- curl.headers = {
40
- 'Accept' => 'application/json',
41
- 'User-Agent' => 'flareshow 0.1'
42
- }
43
- curl.multipart_form_post=true
44
- end
45
- request.http_post(*params)
46
- response = process_response(request)
39
+ # create the request object
40
+ req = Net::HTTP::Post.new(uri.path)
41
+ # set request headers
42
+ req.add_field "Accept", "application/json"
43
+ req.add_field "User-Agent", "ruby flareshow"
44
+ req.add_field "Accept-Encoding", "compress, gzip"
47
45
 
48
- # log a service exception
49
- case response["status_code"]
50
- when 400
51
- log_service_error(response)
52
- when 500
53
- log_service_error(response)
54
- when 403
55
- log_service_error(response)
56
- end
57
-
58
- response
59
- end
60
-
61
- # do a get request
62
- def http_get(url)
63
- request = Curl::Easy.new(url + "?key=#{@key}") do |curl|
64
- curl.headers = {
65
- 'User-Agent' => 'flareshow 0.1'
46
+ # just json
47
+ if !files || files.empty?
48
+ req.add_field "Content-type", "application/json; charset=UTF-8"
49
+ # set the postbody
50
+ req.body = params.to_json
51
+ # handle file params
52
+ else
53
+ params = params.map{|p|
54
+ val = p[1].is_a?(String) ? p[1] : p[1].to_json
55
+ Param.new(p[0], val, "application/json")
66
56
  }
57
+ files.each do |f|
58
+ params << FileParam.new(f["part_id"], f["file_path"], File.read(f["file_path"]))
59
+ end
60
+ body, header = *MultipartPost.prepare_query(params)
61
+ req.add_field "Content-type", header["Content-type"]
62
+ req.body = body
67
63
  end
68
- request.perform()
69
- response = process_response(request)
70
64
 
71
- Flareshow::Util.log_error("resource not found") if response["status_code"] == 404
65
+ # make the request
66
+ http = Net::HTTP.new(uri.host, uri.port)
67
+ http.set_debug_output DEFAULT_LOGGER if debug_output
68
+ response = http.start {|h| h.request(req)}
72
69
 
70
+ # normalize the response
71
+ response = process_response(response)
72
+ log_response(response)
73
73
  response
74
74
  end
75
75
 
76
- # get the interesting bits out of the curl response
77
- def process_response(request)
78
- response = {"status_code" => request.response_code, "headers" => request.header_str, "body" => request.body_str}
79
- if (/json/i).match(request.content_type)
80
- response["resources"] = JSON.parse(response["body"])
81
- end
82
- Flareshow::Util.log_info(response["status_code"])
83
- Flareshow::Util.log_info(response["body"])
76
+ # do a get request
77
+ def http_get(uri)
78
+ uri = URI.parse(uri) unless uri.is_a? URI
79
+ req = Net::HTTP::Get.new(uri.path + "?key=#{@key}")
80
+ req.add_field "User-Agent", "ruby flareshow"
81
+ http = Net::HTTP.new(uri.host, uri.port)
82
+ http.set_debug_output DEFAULT_LOGGER if debug_output
83
+ response = http.start{|h|http.request(req)}
84
+ response = process_response(response)
85
+ Flareshow::Util.log_error("resource not found") if response["status_code"] == 404
84
86
  response
85
87
  end
86
88
 
87
- # log a service error
88
- def log_service_error(response)
89
- if response["resources"]
90
- Flareshow::Util.log_error(response["resources"]["message"])
91
- Flareshow::Util.log_error(response["resources"]["details"])
92
- else
93
- Flareshow::Util.log_error(response["body"])
89
+ # log the response
90
+ def log_response(response)
91
+ # log a service exception
92
+ case response["status_code"]
93
+ when 400
94
+ log_service_error(response)
95
+ when 500
96
+ log_service_error(response)
97
+ when 403
98
+ log_service_error(response)
94
99
  end
95
100
  end
96
101
 
97
102
  # authenticate with the server using an http post
98
103
  def authenticate(login, password)
99
- params = [
100
- Curl::PostField.content("login", login),
101
- Curl::PostField.content("password", password)
102
- ]
104
+ params = {:login => login, :password => password}
103
105
  response = post(auth_endpoint, params)
104
106
  # store the auth token returned from the authentication request
105
107
  if response["status_code"] == 200
@@ -110,59 +112,82 @@ class Flareshow::Service
110
112
  end
111
113
  rescue Exception => e
112
114
  Flareshow::Util.log_error e.message
113
- end
114
-
115
- # clear the authenticated session
116
- def logout
117
- @key = nil
118
- end
119
-
120
- # are we authenticated
121
- def authenticated?
122
- !!@key
115
+ Flareshow::Util.log_error e.backtrace.join("\n")
123
116
  end
124
117
 
125
118
  # query the server with an http post of the query params
126
119
  def query(params={})
127
120
  raise Flareshow::AuthenticationRequired unless @key
128
-
129
- # add the json request parts
130
- params = [
131
- Curl::PostField.content("key", @key, 'application/json'),
132
- Curl::PostField.content("query", params.to_json, 'application/json')
133
- ]
134
-
121
+ params = {"key" => @key, "query" => params}
135
122
  post(api_endpoint, params)
136
123
  end
137
124
 
138
125
  # commit changes to the server with an http post
139
126
  def commit(params={}, files=[])
140
127
  raise Flareshow::AuthenticationRequired unless @key
141
-
142
- curl_params = []
143
- has_files = false
144
- if params["posts"]
145
- # add any file parts passed in and assign a part id to the
146
- params["posts"] = (params["posts"]).map do |f|
147
- if f["files"]
148
- f["files"] = (f["files"]).each do |ff|
149
- has_files = true
150
- curl_params.push(Curl::PostField.file(ff["part_id"], ff["file_path"]))
128
+ params, files = *files_from_params(params) if params["posts"]
129
+ params = {"key" => @key, "data" => params}
130
+ post(api_endpoint, params, files)
131
+ end
132
+
133
+ # get the files out of the params
134
+ def files_from_params(params)
135
+ files = []
136
+ # add any file parts passed in and assign a part id to the
137
+ params["posts"] = (params["posts"]).map do |f|
138
+ if f["files"]
139
+ f["files"] = (f["files"]).map do |ff|
140
+ # we only want to send up new files from the client so we'll strip out any existing
141
+ # files in the params that came down from the server
142
+ val = nil
143
+ if ff["part_id"]
144
+ val = {"part_id" => ff["part_id"], "file_path" => ff["file_path"]}
145
+ files << val
151
146
  end
152
- end
153
- f
147
+ val
148
+ end.compact
154
149
  end
150
+ f
155
151
  end
152
+ [params, files]
153
+ end
154
+
155
+ # get the interesting bits out of the curl response
156
+ def process_response(response)
157
+ # read the response headers
158
+ headers = {}; response.each_header{|k,v| headers[k] = v}
159
+ # build a response object
160
+ response_obj = {"status_code" => response.code.to_i, "headers" => headers, "body" => response.plain_body}
156
161
 
157
- params["files"] = []
158
-
159
- # add the json request parts
160
- curl_params += [
161
- Curl::PostField.content("key", @key, 'application/json'),
162
- Curl::PostField.content("data", params.to_json, 'application/json')
163
- ]
162
+ # automatically handle json response
163
+ if (/json/i).match(response.content_type)
164
+ response_obj["resources"] = JSON.parse(response_obj["body"])
165
+ end
164
166
 
165
- post(api_endpoint, curl_params)
167
+ # log the response
168
+ Flareshow::Util.log_info(response_obj["status_code"])
169
+ Flareshow::Util.log_info(response_obj["body"])
170
+ response_obj
171
+ end
172
+
173
+ # log a service error
174
+ def log_service_error(response)
175
+ if response["resources"]
176
+ Flareshow::Util.log_error(response["resources"]["message"])
177
+ Flareshow::Util.log_error(response["resources"]["details"])
178
+ else
179
+ Flareshow::Util.log_error(response["body"])
180
+ end
181
+ end
182
+
183
+ # clear the authenticated session
184
+ def logout
185
+ @key = nil
186
+ end
187
+
188
+ # are we authenticated
189
+ def authenticated?
190
+ !!@key
166
191
  end
167
192
 
168
193
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zenbe-flareshow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.4
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Will Bailey
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-09-11 00:00:00 -07:00
12
+ date: 2009-09-12 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -72,7 +72,7 @@ dependencies:
72
72
  - !ruby/object:Gem::Version
73
73
  version: "0"
74
74
  version:
75
- description: "TODO: a ruby gem for interacting with the shareflow collaboration service by Zenbe"
75
+ description: a ruby gem for interacting with the shareflow collaboration service by Zenbe
76
76
  email: will.bailey@gmail.com
77
77
  executables: []
78
78
 
@@ -95,8 +95,10 @@ files:
95
95
  - lib/file_attachment.rb
96
96
  - lib/flareshow.rb
97
97
  - lib/flow.rb
98
+ - lib/http_encoding_helper.rb
98
99
  - lib/invitation.rb
99
100
  - lib/membership.rb
101
+ - lib/mime_parts.rb
100
102
  - lib/post.rb
101
103
  - lib/resource.rb
102
104
  - lib/searchable.rb
@@ -131,7 +133,7 @@ rubyforge_project: flareshow
131
133
  rubygems_version: 1.2.0
132
134
  signing_key:
133
135
  specification_version: 3
134
- summary: "TODO: a ruby gem for interacting with the shareflow collaboration service"
136
+ summary: a ruby gem for interacting with the shareflow collaboration service
135
137
  test_files:
136
138
  - test/flareshow_test.rb
137
139
  - test/test_helper.rb