willbailey-flareshow 0.0.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.
- data/Flareshow.gemspec +79 -0
- data/LICENSE +20 -0
- data/README.txt +26 -0
- data/Rakefile +61 -0
- data/TODO +11 -0
- data/VERSION +1 -0
- data/lib/base.rb +337 -0
- data/lib/comment.rb +12 -0
- data/lib/exceptions.rb +3 -0
- data/lib/file_attachment.rb +24 -0
- data/lib/flareshow.rb +21 -0
- data/lib/flow.rb +56 -0
- data/lib/invitation.rb +3 -0
- data/lib/membership.rb +3 -0
- data/lib/post.rb +37 -0
- data/lib/server.rb +2 -0
- data/lib/user.rb +74 -0
- data/lib/util.rb +13 -0
- data/test/flareshow_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +134 -0
data/Flareshow.gemspec
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{flareshow}
|
8
|
+
s.version = "0.0.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Will Bailey"]
|
12
|
+
s.date = %q{2009-09-03}
|
13
|
+
s.description = %q{TODO: a ruby gem for interacting with the shareflow collaboration service by Zenbe}
|
14
|
+
s.email = %q{will.bailey@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.txt"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
"Flareshow.gemspec",
|
21
|
+
"LICENSE",
|
22
|
+
"Rakefile",
|
23
|
+
"TODO",
|
24
|
+
"VERSION",
|
25
|
+
"lib/base.rb",
|
26
|
+
"lib/comment.rb",
|
27
|
+
"lib/exceptions.rb",
|
28
|
+
"lib/file_attachment.rb",
|
29
|
+
"lib/flareshow.rb",
|
30
|
+
"lib/flow.rb",
|
31
|
+
"lib/invitation.rb",
|
32
|
+
"lib/membership.rb",
|
33
|
+
"lib/post.rb",
|
34
|
+
"lib/server.rb",
|
35
|
+
"lib/user.rb",
|
36
|
+
"lib/util.rb",
|
37
|
+
"test/flareshow_test.rb",
|
38
|
+
"test/test_helper.rb"
|
39
|
+
]
|
40
|
+
s.has_rdoc = true
|
41
|
+
s.homepage = %q{http://github.com/willbailey/flareshow}
|
42
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
43
|
+
s.require_paths = ["lib"]
|
44
|
+
s.rubyforge_project = %q{flareshow}
|
45
|
+
s.rubygems_version = %q{1.3.1}
|
46
|
+
s.summary = %q{TODO: a ruby gem for interacting with the shareflow collaboration service}
|
47
|
+
s.test_files = [
|
48
|
+
"test/flareshow_test.rb",
|
49
|
+
"test/test_helper.rb"
|
50
|
+
]
|
51
|
+
|
52
|
+
if s.respond_to? :specification_version then
|
53
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
54
|
+
s.specification_version = 2
|
55
|
+
|
56
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
57
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
58
|
+
s.add_development_dependency(%q<json>, [">= 0"])
|
59
|
+
s.add_development_dependency(%q<curb>, [">= 0"])
|
60
|
+
s.add_development_dependency(%q<facets>, [">= 0"])
|
61
|
+
s.add_development_dependency(%q<facets/dictionary>, [">= 0"])
|
62
|
+
s.add_development_dependency(%q<uuid>, [">= 0"])
|
63
|
+
else
|
64
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
65
|
+
s.add_dependency(%q<json>, [">= 0"])
|
66
|
+
s.add_dependency(%q<curb>, [">= 0"])
|
67
|
+
s.add_dependency(%q<facets>, [">= 0"])
|
68
|
+
s.add_dependency(%q<facets/dictionary>, [">= 0"])
|
69
|
+
s.add_dependency(%q<uuid>, [">= 0"])
|
70
|
+
end
|
71
|
+
else
|
72
|
+
s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
|
73
|
+
s.add_dependency(%q<json>, [">= 0"])
|
74
|
+
s.add_dependency(%q<curb>, [">= 0"])
|
75
|
+
s.add_dependency(%q<facets>, [">= 0"])
|
76
|
+
s.add_dependency(%q<facets/dictionary>, [">= 0"])
|
77
|
+
s.add_dependency(%q<uuid>, [">= 0"])
|
78
|
+
end
|
79
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Will Bailey
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.txt
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
___ ___ __
|
2
|
+
/'___\/\_ \ /\ \
|
3
|
+
/\ \__/\//\ \ __ _ __ __ ____\ \ \___ ___ __ __ __
|
4
|
+
\ \ ,__\ \ \ \ /'__`\ /\`'__\/'__`\ /',__\\ \ _ `\ / __`\/\ \/\ \/\ \
|
5
|
+
\ \ \_/ \_\ \_/\ \L\.\_\ \ \//\ __//\__, `\\ \ \ \ \/\ \L\ \ \ \_/ \_/ \
|
6
|
+
\ \_\ /\____\ \__/.\_\\ \_\\ \____\/\____/ \ \_\ \_\ \____/\ \___x___/'
|
7
|
+
\/_/ \/____/\/__/\/_/ \/_/ \/____/\/___/ \/_/\/_/\/___/ \/__//__/
|
8
|
+
|
9
|
+
~ Client Library For the Zenbe Shareflow API
|
10
|
+
|
11
|
+
Description goes here.
|
12
|
+
|
13
|
+
== Note on Patches/Pull Requests
|
14
|
+
|
15
|
+
* Fork the project.
|
16
|
+
* Make your feature addition or bug fix.
|
17
|
+
* Add tests for it. This is important so I don't break it in a
|
18
|
+
future version unintentionally.
|
19
|
+
* Commit, do not mess with rakefile, version, or history.
|
20
|
+
(if you want to have your own version, that is fine but
|
21
|
+
bump version in a commit by itself I can ignore when I pull)
|
22
|
+
* Send me a pull request. Bonus points for topic branches.
|
23
|
+
|
24
|
+
== Copyright
|
25
|
+
|
26
|
+
Copyright (c) 2009 Will Bailey. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "flareshow"
|
8
|
+
gem.summary = %Q{TODO: a ruby gem for interacting with the shareflow collaboration service}
|
9
|
+
gem.description = %Q{TODO: a ruby gem for interacting with the shareflow collaboration service by Zenbe}
|
10
|
+
gem.email = "will.bailey@gmail.com"
|
11
|
+
gem.homepage = "http://github.com/willbailey/flareshow"
|
12
|
+
gem.authors = ["Will Bailey"]
|
13
|
+
gem.add_development_dependency "thoughtbot-shoulda"
|
14
|
+
gem.add_development_dependency "json"
|
15
|
+
gem.add_development_dependency "curb"
|
16
|
+
gem.add_development_dependency "facets"
|
17
|
+
gem.add_development_dependency "facets/dictionary"
|
18
|
+
gem.add_development_dependency "uuid"
|
19
|
+
gem.rubyforge_project = "flareshow"
|
20
|
+
end
|
21
|
+
rescue LoadError
|
22
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
23
|
+
end
|
24
|
+
|
25
|
+
require 'rake/testtask'
|
26
|
+
Rake::TestTask.new(:test) do |test|
|
27
|
+
test.libs << 'lib' << 'test'
|
28
|
+
test.pattern = 'test/**/*_test.rb'
|
29
|
+
test.verbose = true
|
30
|
+
end
|
31
|
+
|
32
|
+
begin
|
33
|
+
require 'rcov/rcovtask'
|
34
|
+
Rcov::RcovTask.new do |test|
|
35
|
+
test.libs << 'test'
|
36
|
+
test.pattern = 'test/**/*_test.rb'
|
37
|
+
test.verbose = true
|
38
|
+
end
|
39
|
+
rescue LoadError
|
40
|
+
task :rcov do
|
41
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
task :test => :check_dependencies
|
46
|
+
|
47
|
+
task :default => :test
|
48
|
+
|
49
|
+
require 'rake/rdoctask'
|
50
|
+
Rake::RDocTask.new do |rdoc|
|
51
|
+
if File.exist?('VERSION')
|
52
|
+
version = File.read('VERSION')
|
53
|
+
else
|
54
|
+
version = ""
|
55
|
+
end
|
56
|
+
|
57
|
+
rdoc.rdoc_dir = 'rdoc'
|
58
|
+
rdoc.title = "flareshow #{version}"
|
59
|
+
rdoc.rdoc_files.include('README*')
|
60
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
61
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
TODO:
|
2
|
+
flesh out more resource methods
|
3
|
+
make post requests with embedded file attachments respond with the file attachments for now...later we need to allow the creation of files in the same way as posts as flat
|
4
|
+
namespaced objects
|
5
|
+
remove temporary auth setup logging in user automatically
|
6
|
+
handle failure states on requests
|
7
|
+
|
8
|
+
TODONE:
|
9
|
+
|
10
|
+
QUESTIONS:
|
11
|
+
should authentication responses look like query and commit responses namespacing is applied differently in authentication currently?
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/base.rb
ADDED
@@ -0,0 +1,337 @@
|
|
1
|
+
module Flareshow
|
2
|
+
|
3
|
+
# default parameters that are included with query
|
4
|
+
# requests unless they are explicitly overridden
|
5
|
+
DEFAULT_PARAMS = {:order => "created_at desc"} unless defined? DEFAULT_PARAMS
|
6
|
+
|
7
|
+
# mappings to allow easy conversion from the
|
8
|
+
# response keys the server sends back in JSUP
|
9
|
+
# messages
|
10
|
+
ResourceToClassMap = {
|
11
|
+
"flows" => "Flow",
|
12
|
+
"posts" => "Post",
|
13
|
+
"comments" => "Comment",
|
14
|
+
"files" => "FileAttachment",
|
15
|
+
"memberships" => "Membership",
|
16
|
+
"invitations" => "Invitation",
|
17
|
+
"users" => "User"
|
18
|
+
} unless defined? ResourceToClassMap
|
19
|
+
ClassToResourceMap = ResourceToClassMap.invert unless defined? ClassToResourceMap
|
20
|
+
|
21
|
+
# the base class for Flareshow can be inherited from to create Shareflow resource
|
22
|
+
# classes or the class methods can be used to interact with the API directly
|
23
|
+
class Base
|
24
|
+
# =================
|
25
|
+
# = Class Methods =
|
26
|
+
# =================
|
27
|
+
class << self
|
28
|
+
attr_accessor :server
|
29
|
+
|
30
|
+
# return the authentication endpoint for a given host and domain
|
31
|
+
def auth_endpoint
|
32
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/api/v2/auth.json"
|
33
|
+
end
|
34
|
+
|
35
|
+
# return the api endpoint for a given host and domain
|
36
|
+
def api_endpoint
|
37
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/api/v2.json"
|
38
|
+
end
|
39
|
+
|
40
|
+
# has the server been configured?
|
41
|
+
def server_defined?
|
42
|
+
!!Flareshow::Base.server
|
43
|
+
end
|
44
|
+
|
45
|
+
# make a post request to an endpoint
|
46
|
+
# returns a hash of
|
47
|
+
# - status code
|
48
|
+
# - headers
|
49
|
+
# - body
|
50
|
+
def post(url, params)
|
51
|
+
raise ConfigurationException unless server_defined?
|
52
|
+
request = Curl::Easy.new(url) do |curl|
|
53
|
+
curl.headers = {
|
54
|
+
'Accept' => 'application/json',
|
55
|
+
'User-Agent' => 'flareshow 0.1'
|
56
|
+
}
|
57
|
+
curl.multipart_form_post=true
|
58
|
+
end
|
59
|
+
request.http_post(*params)
|
60
|
+
process_response(request)
|
61
|
+
end
|
62
|
+
|
63
|
+
# do a get request
|
64
|
+
def http_get(url)
|
65
|
+
request = Curl::Easy.new(url + "?key=#{User.current.get("auth_token")}") do |curl|
|
66
|
+
curl.headers = {
|
67
|
+
'User-Agent' => 'flareshow 0.1'
|
68
|
+
}
|
69
|
+
end
|
70
|
+
request.perform()
|
71
|
+
request.body_str
|
72
|
+
end
|
73
|
+
|
74
|
+
# authenticate with the server
|
75
|
+
def authenticate(params={}, callbacks={})
|
76
|
+
params = [
|
77
|
+
Curl::PostField.content("login", params[:login]),
|
78
|
+
Curl::PostField.content("password", params[:password])
|
79
|
+
]
|
80
|
+
response = post(auth_endpoint, params)
|
81
|
+
handle_response(response, callbacks)
|
82
|
+
end
|
83
|
+
|
84
|
+
# query the server
|
85
|
+
def query(params={}, callbacks={})
|
86
|
+
raise UserRequiredException unless User.current
|
87
|
+
|
88
|
+
# add the json request parts
|
89
|
+
params = [
|
90
|
+
Curl::PostField.content("key", User.current.get("auth_token"), 'application/json'),
|
91
|
+
Curl::PostField.content("query", params.to_json, 'application/json')
|
92
|
+
]
|
93
|
+
|
94
|
+
response = post(api_endpoint, params)
|
95
|
+
results = assimilate_resources(response) if response[:status_code] == 200
|
96
|
+
handle_response(response,callbacks,results)
|
97
|
+
end
|
98
|
+
|
99
|
+
# commit changes to the server
|
100
|
+
def commit(params={}, callbacks={}, files=[])
|
101
|
+
curl_params = []
|
102
|
+
has_files = false
|
103
|
+
if params["posts"]
|
104
|
+
# add any file parts passed in and assign a part id to the
|
105
|
+
params["posts"] = (params["posts"]).map do |f|
|
106
|
+
if f["files"]
|
107
|
+
f["files"] = (f["files"]).each do |ff|
|
108
|
+
has_files = true
|
109
|
+
curl_params.push(Curl::PostField.file(ff["part_id"], ff["file_path"]))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
f
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
params["files"] = []
|
117
|
+
|
118
|
+
# add the json request parts
|
119
|
+
curl_params += [
|
120
|
+
Curl::PostField.content("key", User.current.get("auth_token"), 'application/json'),
|
121
|
+
Curl::PostField.content("data", params.to_json, 'application/json')
|
122
|
+
]
|
123
|
+
|
124
|
+
response = post(api_endpoint, curl_params)
|
125
|
+
results = assimilate_resources(response) if response[:status_code] == 200
|
126
|
+
handle_response(response,callbacks,results)
|
127
|
+
end
|
128
|
+
|
129
|
+
# return the results directly or invoke callbacks if provided
|
130
|
+
def handle_response(response, callbacks={}, results=nil)
|
131
|
+
if callbacks.empty?
|
132
|
+
results
|
133
|
+
else
|
134
|
+
dispatch(response, callbacks)
|
135
|
+
true
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# get the interesting bits out of the curl response
|
140
|
+
def process_response(request)
|
141
|
+
response = {:status_code => request.response_code, :headers => request.header_str, :body => JSON.parse(request.body_str)}
|
142
|
+
Util.log_info JSON.pretty_generate(response)
|
143
|
+
response
|
144
|
+
end
|
145
|
+
|
146
|
+
# assimilate the resources provided in the response
|
147
|
+
def assimilate_resources(response)
|
148
|
+
results = {}
|
149
|
+
# process each resource key and generate a new object
|
150
|
+
# or merge the object data with an existing object
|
151
|
+
response[:body].each do |resource_pair|
|
152
|
+
resource_key, resources = resource_pair[0], resource_pair[1]
|
153
|
+
klass = Kernel.const_get(Flareshow::ResourceToClassMap[resource_key])
|
154
|
+
next unless klass
|
155
|
+
resources.each do |resource_data|
|
156
|
+
item = klass.get(resource_data["id"], :server)
|
157
|
+
item.update(resource_data, :server)
|
158
|
+
results[resource_key] ||= []
|
159
|
+
results[resource_key].push(item)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
results
|
163
|
+
end
|
164
|
+
|
165
|
+
# dispatch a request to the appropriate callback
|
166
|
+
def dispatch(response, callbacks={})
|
167
|
+
case response[:status_code]
|
168
|
+
when 200...201
|
169
|
+
callbacks[:on_success].call(response[:body]) if callbacks[:on_success]
|
170
|
+
else
|
171
|
+
callbacks[:on_failure].call(response[:body]) if callbacks[:on_failure]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# find an existing instance of this object in the client or create a new one
|
176
|
+
def get(id_or_object, source = :client)
|
177
|
+
o = if id_or_object.is_a?(String) || id_or_object.is_a?(Integer)
|
178
|
+
id = id_or_object.to_s
|
179
|
+
store[id] ||= new({"id" => id}, source)
|
180
|
+
elsif
|
181
|
+
id = id_or_object["id"]
|
182
|
+
store[id] ||= new(id_or_object, source)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# list out the instances in memory
|
187
|
+
def list
|
188
|
+
store.each_value do |v|
|
189
|
+
Util.log_info(v.inspect)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
# get all the resources of this type from the server
|
194
|
+
def all
|
195
|
+
key = Flareshow::ClassToResourceMap[self.name]
|
196
|
+
params = DEFAULT_PARAMS
|
197
|
+
self.query({key => params})
|
198
|
+
end
|
199
|
+
|
200
|
+
# find a resource by querying the server
|
201
|
+
def find(params)
|
202
|
+
key = Flareshow::ClassToResourceMap[self.name]
|
203
|
+
params = DEFAULT_PARAMS.merge(params)
|
204
|
+
(self.query({key => params}) || {})[key]
|
205
|
+
end
|
206
|
+
|
207
|
+
# return the first resource in the client store
|
208
|
+
# or go to the server and fetch one item
|
209
|
+
def first
|
210
|
+
return store.first if store.size > 0
|
211
|
+
find({:limit => 1})
|
212
|
+
return store.first
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
# create a resource local and sync it to the server
|
217
|
+
def create(params)
|
218
|
+
new(params).save
|
219
|
+
end
|
220
|
+
|
221
|
+
def store
|
222
|
+
@objects ||= Dictionary.new
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
|
227
|
+
# ====================
|
228
|
+
# = Instance Methods =
|
229
|
+
# ====================
|
230
|
+
|
231
|
+
# constructor
|
232
|
+
# build a new Flareshow::Base resource
|
233
|
+
def initialize(data={}, source = :client)
|
234
|
+
@data = {}
|
235
|
+
data["id"] = UUID.generate.upcase if source == :client
|
236
|
+
update(data, source)
|
237
|
+
end
|
238
|
+
|
239
|
+
# ==============================
|
240
|
+
# = Server Persistence Actions =
|
241
|
+
# ==============================
|
242
|
+
|
243
|
+
# reload the resource from the server
|
244
|
+
def refresh(callbacks={})
|
245
|
+
key = Flareshow::ClassToResourceMap[self.class.name]
|
246
|
+
results = self.class.query({key => {"id" => id}}, callbacks)
|
247
|
+
mark_destroyed! if results.empty?
|
248
|
+
self
|
249
|
+
end
|
250
|
+
|
251
|
+
# save a resource to the server
|
252
|
+
def save(callbacks={})
|
253
|
+
key = Flareshow::ClassToResourceMap[self.class.name]
|
254
|
+
self.class.commit({key => [(self.changes || {}).merge({"id" => id})] }, callbacks)
|
255
|
+
self
|
256
|
+
end
|
257
|
+
|
258
|
+
# destroy the resource on the server
|
259
|
+
def destroy(callbacks={})
|
260
|
+
key = Flareshow::ClassToResourceMap[self.class.name]
|
261
|
+
self.class.commit({key => [{"id" => id, "_removed" => true}]}, callbacks)
|
262
|
+
mark_destroyed!
|
263
|
+
self
|
264
|
+
end
|
265
|
+
|
266
|
+
# has this resource been destroyed
|
267
|
+
def destroyed?
|
268
|
+
self._removed || self.frozen?
|
269
|
+
end
|
270
|
+
|
271
|
+
private
|
272
|
+
|
273
|
+
def mark_destroyed!
|
274
|
+
self.freeze
|
275
|
+
self._removed=true
|
276
|
+
self.class.store.delete(id)
|
277
|
+
end
|
278
|
+
|
279
|
+
public
|
280
|
+
|
281
|
+
# ==================================
|
282
|
+
# = Attribute and State Management =
|
283
|
+
# ==================================
|
284
|
+
|
285
|
+
# return the server id of a resource
|
286
|
+
def id
|
287
|
+
@data["id"]
|
288
|
+
end
|
289
|
+
|
290
|
+
# update the instance data for this resource
|
291
|
+
# keeping track of dirty state if the update came from
|
292
|
+
# the client
|
293
|
+
def update(attributes, source = :client)
|
294
|
+
attributes.each do |p|
|
295
|
+
key, value = p[0], p[1]
|
296
|
+
self.set(key, value, source)
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
# keep track of dirty state on the client by maintaining a copy
|
301
|
+
# of the original state of each intstance variable when it is provided by
|
302
|
+
# the server
|
303
|
+
def set(key, value, source = :client)
|
304
|
+
# Util.log_info("setting #{key} : #{value}")
|
305
|
+
@data["original_#{key}"] = value if source == :server
|
306
|
+
@data[key.to_s]=value
|
307
|
+
end
|
308
|
+
|
309
|
+
# get a data value
|
310
|
+
def get(key)
|
311
|
+
@data[key]
|
312
|
+
end
|
313
|
+
|
314
|
+
# all the state that has been modified on the client
|
315
|
+
def changes
|
316
|
+
attributes = @data.inject({}) do |memo, pair|
|
317
|
+
key, value = *pair
|
318
|
+
if @data[key] != @data["original_#{key}"] && !key.to_s.match(/original/)
|
319
|
+
memo[key] = value
|
320
|
+
end
|
321
|
+
memo
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
# fallback to getter or setter
|
326
|
+
def method_missing(meth, *args)
|
327
|
+
meth = meth.to_s
|
328
|
+
meth.match(/\=/) ? set(meth.gsub(/\=/,''), *args) : get(meth)
|
329
|
+
end
|
330
|
+
|
331
|
+
# has this model been removed on the server
|
332
|
+
def method_name
|
333
|
+
!!self._removed
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
end
|
data/lib/comment.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
class Comment < Flareshow::Base
|
2
|
+
|
3
|
+
# permalink to this comment
|
4
|
+
def permalink(mobile=false)
|
5
|
+
if mobile
|
6
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/mobile/post/#{reply_to}"
|
7
|
+
else
|
8
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/p/#{reply_to}?comment_id#{id}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/exceptions.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
class FileAttachment < Flareshow::Base
|
2
|
+
|
3
|
+
# =================
|
4
|
+
# = Class Methods =
|
5
|
+
# =================
|
6
|
+
class << self
|
7
|
+
# file attachments has a resource key of files
|
8
|
+
# for querying the server
|
9
|
+
def resource_key
|
10
|
+
"files"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
# download the file contents
|
15
|
+
def download
|
16
|
+
url = self.url
|
17
|
+
unless url.match(/http/)
|
18
|
+
url = "http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}#{url}"
|
19
|
+
end
|
20
|
+
Util.log_info("getting #{url}")
|
21
|
+
self.class.http_get(url)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
data/lib/flareshow.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
ROOT = File.dirname(__FILE__) unless defined? ROOT
|
2
|
+
|
3
|
+
# gems
|
4
|
+
require 'rubygems' #TODO fix
|
5
|
+
require 'json'
|
6
|
+
require 'curb'
|
7
|
+
require 'facets'
|
8
|
+
require 'facets/dictionary'
|
9
|
+
require 'uuid'
|
10
|
+
|
11
|
+
# std lib
|
12
|
+
require 'ostruct'
|
13
|
+
require 'logger'
|
14
|
+
|
15
|
+
# app
|
16
|
+
require 'base'
|
17
|
+
|
18
|
+
# logging
|
19
|
+
DEFAULT_LOGGER = Logger.new(STDOUT) unless defined?(DEFAULT_LOGGER)
|
20
|
+
|
21
|
+
Dir.glob(File.join(ROOT, "*.rb")).each{|lib| require lib}
|
data/lib/flow.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
class Flow < Flareshow::Base
|
2
|
+
|
3
|
+
# =================
|
4
|
+
# = Class Methods =
|
5
|
+
# =================
|
6
|
+
class << self
|
7
|
+
# find a flow by name
|
8
|
+
def find_by_name(name)
|
9
|
+
self.find({:name => name})
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
# permalink for this flow
|
14
|
+
def permalink(mobile=false)
|
15
|
+
if mobile
|
16
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/mobile/flows/#{id}"
|
17
|
+
else
|
18
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/c/#{id}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#invite/reinvite a user to a flow by email address
|
23
|
+
def send_invitions(email_addresses)
|
24
|
+
self.invite = [email_addresses].flatten
|
25
|
+
self.save
|
26
|
+
end
|
27
|
+
|
28
|
+
# uninvite an invited user from a flow by email address
|
29
|
+
def revoke_invitations(email_addresses)
|
30
|
+
self.uninvite = [email_addresses].flatten
|
31
|
+
self.save
|
32
|
+
end
|
33
|
+
|
34
|
+
# remove a user from a flow
|
35
|
+
# you must be the owner of the flow to perform
|
36
|
+
# this action
|
37
|
+
def remove_members(member_ids)
|
38
|
+
self.remove_members = [email_addresses].flatten
|
39
|
+
self.save
|
40
|
+
end
|
41
|
+
|
42
|
+
# build a new post but don't persist it immediatel
|
43
|
+
def build_post(attributes)
|
44
|
+
post = Post.new
|
45
|
+
post.update(attributes)
|
46
|
+
post.flow_id = id
|
47
|
+
post
|
48
|
+
end
|
49
|
+
|
50
|
+
# create a new post in this flow
|
51
|
+
def create_post(attributes)
|
52
|
+
p=build_post(attributes)
|
53
|
+
p.save
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/invitation.rb
ADDED
data/lib/membership.rb
ADDED
data/lib/post.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
class Post < Flareshow::Base
|
2
|
+
|
3
|
+
# permalink to this post
|
4
|
+
def permalink(mobile=false)
|
5
|
+
if mobile
|
6
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/mobile/post/#{id}"
|
7
|
+
else
|
8
|
+
"http://#{Flareshow::Base.server.host}/#{Flareshow::Base.server.domain}/shareflow/p/#{id}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# build a new comment but don't immediately persist it
|
13
|
+
def build_comment(attributes={})
|
14
|
+
c = Comment.new(attributes)
|
15
|
+
c.post_id = self.id
|
16
|
+
c
|
17
|
+
end
|
18
|
+
|
19
|
+
# create a new comment on the post
|
20
|
+
def create_comment(attributes={})
|
21
|
+
c = build_comment(attributes)
|
22
|
+
c.save
|
23
|
+
end
|
24
|
+
|
25
|
+
def build_file(file_path)
|
26
|
+
self.files ||= []
|
27
|
+
self.files += [{"part_id" => "file_#{UUID.generate}", "file_path" => file_path}]
|
28
|
+
end
|
29
|
+
|
30
|
+
# upload a file to a post
|
31
|
+
def create_file(file_path)
|
32
|
+
self.files = []
|
33
|
+
self.build_file(file_path)
|
34
|
+
self.save
|
35
|
+
self.files = nil
|
36
|
+
end
|
37
|
+
end
|
data/lib/server.rb
ADDED
data/lib/user.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
class User < Flareshow::Base
|
2
|
+
|
3
|
+
# =================
|
4
|
+
# = Class Methods =
|
5
|
+
# =================
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# return the current authenticated user
|
9
|
+
def current
|
10
|
+
@current
|
11
|
+
end
|
12
|
+
|
13
|
+
# authenticate user credentials
|
14
|
+
def log_in(login, password)
|
15
|
+
authenticate({:login => login, :password => password},
|
16
|
+
{
|
17
|
+
:on_success => method(:on_authentication_success),
|
18
|
+
:on_failure => method(:on_authentication_failure)
|
19
|
+
}
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# =============
|
26
|
+
# = Callbacks =
|
27
|
+
# =============
|
28
|
+
# login success callback
|
29
|
+
def on_authentication_success(response_body)
|
30
|
+
@current = User.get(response_body["data"], :server)
|
31
|
+
end
|
32
|
+
|
33
|
+
# login failed callback
|
34
|
+
def on_authentication_failure(response_body)
|
35
|
+
Util.log_error("failed to login: #{response_body}")
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
# ====================
|
41
|
+
# = Instance Methods =
|
42
|
+
# ====================
|
43
|
+
|
44
|
+
# ================
|
45
|
+
# = Associations =
|
46
|
+
# ================
|
47
|
+
def flows
|
48
|
+
Flow.find({"user_id" => {"in" => id}})
|
49
|
+
end
|
50
|
+
|
51
|
+
def posts
|
52
|
+
Post.find({"user_id" => {"in" => id}})
|
53
|
+
end
|
54
|
+
|
55
|
+
def comments
|
56
|
+
Comment.find({"user_id" => {"in" => id}})
|
57
|
+
end
|
58
|
+
|
59
|
+
def files
|
60
|
+
FileAttachment.find({"user_id" => {"in" => id}})
|
61
|
+
end
|
62
|
+
|
63
|
+
# ==================
|
64
|
+
# = Authentication =
|
65
|
+
# ==================
|
66
|
+
def logout
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
def logged_in?
|
71
|
+
auth_token
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
data/lib/util.rb
ADDED
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: willbailey-flareshow
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Will Bailey
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-09-03 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: thoughtbot-shoulda
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: json
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: curb
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: facets
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: facets/dictionary
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: uuid
|
67
|
+
type: :development
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
description: "TODO: a ruby gem for interacting with the shareflow collaboration service by Zenbe"
|
76
|
+
email: will.bailey@gmail.com
|
77
|
+
executables: []
|
78
|
+
|
79
|
+
extensions: []
|
80
|
+
|
81
|
+
extra_rdoc_files:
|
82
|
+
- LICENSE
|
83
|
+
- README.txt
|
84
|
+
files:
|
85
|
+
- Flareshow.gemspec
|
86
|
+
- LICENSE
|
87
|
+
- Rakefile
|
88
|
+
- TODO
|
89
|
+
- VERSION
|
90
|
+
- lib/base.rb
|
91
|
+
- lib/comment.rb
|
92
|
+
- lib/exceptions.rb
|
93
|
+
- lib/file_attachment.rb
|
94
|
+
- lib/flareshow.rb
|
95
|
+
- lib/flow.rb
|
96
|
+
- lib/invitation.rb
|
97
|
+
- lib/membership.rb
|
98
|
+
- lib/post.rb
|
99
|
+
- lib/server.rb
|
100
|
+
- lib/user.rb
|
101
|
+
- lib/util.rb
|
102
|
+
- test/flareshow_test.rb
|
103
|
+
- test/test_helper.rb
|
104
|
+
- README.txt
|
105
|
+
has_rdoc: true
|
106
|
+
homepage: http://github.com/willbailey/flareshow
|
107
|
+
licenses:
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options:
|
110
|
+
- --charset=UTF-8
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: "0"
|
118
|
+
version:
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: "0"
|
124
|
+
version:
|
125
|
+
requirements: []
|
126
|
+
|
127
|
+
rubyforge_project: flareshow
|
128
|
+
rubygems_version: 1.3.5
|
129
|
+
signing_key:
|
130
|
+
specification_version: 2
|
131
|
+
summary: "TODO: a ruby gem for interacting with the shareflow collaboration service"
|
132
|
+
test_files:
|
133
|
+
- test/flareshow_test.rb
|
134
|
+
- test/test_helper.rb
|