zenbe-flareshow 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Flareshow.gemspec +7 -5
- data/README.md +4 -4
- data/VERSION +1 -1
- data/lib/flareshow.rb +6 -2
- data/lib/http_encoding_helper.rb +49 -0
- data/lib/mime_parts.rb +37 -0
- data/lib/resource.rb +1 -0
- data/lib/service.rb +115 -90
- metadata +6 -4
data/Flareshow.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{flareshow}
|
8
|
-
s.version = "0.
|
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-
|
13
|
-
s.description = %q{
|
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.
|
50
|
-
s.summary = %q{
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
1
|
+
0.3.0
|
data/lib/flareshow.rb
CHANGED
@@ -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 '
|
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
|
data/lib/mime_parts.rb
ADDED
@@ -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
|
data/lib/resource.rb
CHANGED
data/lib/service.rb
CHANGED
@@ -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(
|
37
|
+
def post(uri, params, files=[])
|
37
38
|
raise Flareshow::ConfigurationException unless server_defined?
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
#
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
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
|
-
#
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
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
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
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
|
-
|
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
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
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
|
-
|
153
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
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.
|
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-
|
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:
|
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:
|
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
|