flareshow 0.3.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/.gitignore +1 -0
- data/Flareshow.gemspec +82 -0
- data/LICENSE +20 -0
- data/README.md +122 -0
- data/Rakefile +60 -0
- data/TODO +14 -0
- data/VERSION +1 -0
- data/lib/cache.rb +91 -0
- data/lib/comment.rb +28 -0
- data/lib/exceptions.rb +32 -0
- data/lib/file_attachment.rb +40 -0
- data/lib/flareshow.rb +61 -0
- data/lib/flow.rb +78 -0
- data/lib/http_encoding_helper.rb +49 -0
- data/lib/invitation.rb +16 -0
- data/lib/membership.rb +3 -0
- data/lib/mime_parts.rb +37 -0
- data/lib/post.rb +65 -0
- data/lib/resource.rb +205 -0
- data/lib/searchable.rb +9 -0
- data/lib/server.rb +2 -0
- data/lib/service.rb +195 -0
- data/lib/user.rb +60 -0
- data/lib/util.rb +13 -0
- data/test/flareshow_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +131 -0
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
*.gem
|
data/Flareshow.gemspec
ADDED
@@ -0,0 +1,82 @@
|
|
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.3.1"
|
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{2010-01-11}
|
13
|
+
s.description = %q{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.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".gitignore",
|
21
|
+
"Flareshow.gemspec",
|
22
|
+
"LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"TODO",
|
26
|
+
"VERSION",
|
27
|
+
"lib/cache.rb",
|
28
|
+
"lib/comment.rb",
|
29
|
+
"lib/exceptions.rb",
|
30
|
+
"lib/file_attachment.rb",
|
31
|
+
"lib/flareshow.rb",
|
32
|
+
"lib/flow.rb",
|
33
|
+
"lib/http_encoding_helper.rb",
|
34
|
+
"lib/invitation.rb",
|
35
|
+
"lib/membership.rb",
|
36
|
+
"lib/mime_parts.rb",
|
37
|
+
"lib/post.rb",
|
38
|
+
"lib/resource.rb",
|
39
|
+
"lib/searchable.rb",
|
40
|
+
"lib/server.rb",
|
41
|
+
"lib/service.rb",
|
42
|
+
"lib/user.rb",
|
43
|
+
"lib/util.rb",
|
44
|
+
"test/flareshow_test.rb",
|
45
|
+
"test/test_helper.rb"
|
46
|
+
]
|
47
|
+
s.homepage = %q{http://github.com/willbailey/flareshow}
|
48
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
49
|
+
s.require_paths = ["lib"]
|
50
|
+
s.rubyforge_project = %q{flareshow}
|
51
|
+
s.rubygems_version = %q{1.3.5}
|
52
|
+
s.summary = %q{a ruby gem for interacting with the shareflow collaboration service}
|
53
|
+
s.test_files = [
|
54
|
+
"test/flareshow_test.rb",
|
55
|
+
"test/test_helper.rb"
|
56
|
+
]
|
57
|
+
|
58
|
+
if s.respond_to? :specification_version then
|
59
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
60
|
+
s.specification_version = 3
|
61
|
+
|
62
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
63
|
+
s.add_development_dependency(%q<thoughtbot-shoulda>, ["> 0"])
|
64
|
+
s.add_runtime_dependency(%q<json>, ["> 0"])
|
65
|
+
s.add_runtime_dependency(%q<curb>, ["> 0"])
|
66
|
+
s.add_runtime_dependency(%q<facets>, ["> 0"])
|
67
|
+
s.add_runtime_dependency(%q<uuid>, ["> 0"])
|
68
|
+
else
|
69
|
+
s.add_dependency(%q<thoughtbot-shoulda>, ["> 0"])
|
70
|
+
s.add_dependency(%q<json>, ["> 0"])
|
71
|
+
s.add_dependency(%q<curb>, ["> 0"])
|
72
|
+
s.add_dependency(%q<facets>, ["> 0"])
|
73
|
+
s.add_dependency(%q<uuid>, ["> 0"])
|
74
|
+
end
|
75
|
+
else
|
76
|
+
s.add_dependency(%q<thoughtbot-shoulda>, ["> 0"])
|
77
|
+
s.add_dependency(%q<json>, ["> 0"])
|
78
|
+
s.add_dependency(%q<curb>, ["> 0"])
|
79
|
+
s.add_dependency(%q<facets>, ["> 0"])
|
80
|
+
s.add_dependency(%q<uuid>, ["> 0"])
|
81
|
+
end
|
82
|
+
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.md
ADDED
@@ -0,0 +1,122 @@
|
|
1
|
+
___ ___ __
|
2
|
+
/'___\\_ \ /\ \
|
3
|
+
/\ \__///\ \ __ _ __ __ ____\ \ \___ ___ __ __ __
|
4
|
+
\ \ ,__\\ \ \ /'__`\ /\`'__\'__`\ /',__\\ \ _ `\ / __`\/\ \/\ \/\ \
|
5
|
+
\ \ \_/ \_\ \_/\ \L\.\_\ \ \/\ __//\__, `\\ \ \ \ \/\ \L\ \ \ \_/ \_/ \
|
6
|
+
\ \_\ /\____\ \__/.\_\\ \_\ \____\/\____/ \ \_\ \_\ \____/\ \___x___/'
|
7
|
+
\/_/ \/____/\/__/\/_/ \/_/\/____/\/___/ \/_/\/_/\/___/ \/__//__/
|
8
|
+
|
9
|
+
~ a ruby wrapper for the Zenbe Shareflow API
|
10
|
+
|
11
|
+
|
12
|
+
### Overview
|
13
|
+
|
14
|
+
Flareshow provides a ruby wrapper around the shareflow json rpc wire protocol.
|
15
|
+
|
16
|
+
For more information about the Shareflow API see:
|
17
|
+
<http://docs.google.com/View?id=dchr4h9d_5gz6nw3cb>
|
18
|
+
|
19
|
+
### Getting Started
|
20
|
+
You'll need a shareflow account setup before you can begin interacting with the api. Go to <http://getshareflow.com> and sign up for a free account.
|
21
|
+
|
22
|
+
### Authentication
|
23
|
+
|
24
|
+
All actions in Flareshow require authenticationFlareshow can automatically authenticate you against your shareflow server. Just create a YAML formatted .flareshowrc file in your home directory with the following keys
|
25
|
+
|
26
|
+
subdomain : demo.zenbe.com
|
27
|
+
login : demo
|
28
|
+
password : password
|
29
|
+
|
30
|
+
To authenticate manually do the following:
|
31
|
+
|
32
|
+
Flareshow::Service.configure(<subdomain>)
|
33
|
+
Flareshow.authenticate(<login>, <password>)
|
34
|
+
|
35
|
+
### Usage
|
36
|
+
|
37
|
+
Once you've authenticated you can choose to use either interact directly with the Flareshow::Service or use the Flareshow::Resource domain models which encapsulate the domain logic of Shareflow providing a friendlier development environment.
|
38
|
+
|
39
|
+
### Examples
|
40
|
+
|
41
|
+
#### accessing models and associations
|
42
|
+
|
43
|
+
Flareshow offers an ActiveRecord like syntax for retrieving and manipulating models.
|
44
|
+
|
45
|
+
# Get the first post from the server ordered by creation date by default
|
46
|
+
p = Post.first
|
47
|
+
|
48
|
+
# Get the comments for that post
|
49
|
+
p.comments
|
50
|
+
|
51
|
+
# get the file attachments for the post
|
52
|
+
files = p.files
|
53
|
+
|
54
|
+
# download a file
|
55
|
+
files.first.download
|
56
|
+
|
57
|
+
|
58
|
+
#### reading posts
|
59
|
+
|
60
|
+
# the following code will read all posts on the server in a loop
|
61
|
+
per_request = 30
|
62
|
+
results = []
|
63
|
+
offset = 0
|
64
|
+
|
65
|
+
loop do
|
66
|
+
posts = Post.find(:offset => offset, :limit => per_request)
|
67
|
+
results += posts
|
68
|
+
puts results.size
|
69
|
+
offset += per_request
|
70
|
+
break if posts.empty?
|
71
|
+
end
|
72
|
+
|
73
|
+
#### upload a file to a Post
|
74
|
+
|
75
|
+
p=Post.new()
|
76
|
+
p.save
|
77
|
+
p.create_file("/path/to/your/file")
|
78
|
+
|
79
|
+
#### searching for a post
|
80
|
+
|
81
|
+
# posts, files, comments include the searchable mixin
|
82
|
+
# and can be searched using full text search capabilities
|
83
|
+
# on the server
|
84
|
+
results = Post.search("some keywords")
|
85
|
+
|
86
|
+
#### deleting a post or comment
|
87
|
+
|
88
|
+
Post.first.destroy
|
89
|
+
Comment.first.destroy
|
90
|
+
|
91
|
+
#### renaming a flow
|
92
|
+
|
93
|
+
f=Flow.find_by_name('test')
|
94
|
+
f.name = 'a different name'
|
95
|
+
f.save
|
96
|
+
|
97
|
+
#### inviting someone to a flow (only available if you are the creator of the flow)
|
98
|
+
|
99
|
+
f=Flow.find_by_name('test')
|
100
|
+
f.send_invitations('test@test.com')
|
101
|
+
|
102
|
+
# this also works
|
103
|
+
f.send_invitations(['test1@test.com', 'test2@test.com'])
|
104
|
+
|
105
|
+
#### canceling an invitation to a flow (only available if you are the creator of the flow)
|
106
|
+
|
107
|
+
f=Flow.find_by_name('test')
|
108
|
+
# revoke an invitation by the email address that was invited
|
109
|
+
f.revoke_invitations('test@test.com')
|
110
|
+
|
111
|
+
|
112
|
+
#### removing a user from a flow (only available if you are the creator of the flow)
|
113
|
+
|
114
|
+
f = Flow.find_by_name('test')
|
115
|
+
users = f.list_users # get a listing of the users on the flow
|
116
|
+
# remove the last user in the list from the flow...you cant remove yourself in this way
|
117
|
+
f.remove_members(users.last.id)
|
118
|
+
|
119
|
+
#### listing all the users on a flow
|
120
|
+
|
121
|
+
f=Flow.first
|
122
|
+
f.list_users
|
data/Rakefile
ADDED
@@ -0,0 +1,60 @@
|
|
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{a ruby gem for interacting with the shareflow collaboration service}
|
9
|
+
gem.description = %Q{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", "> 0"
|
14
|
+
gem.add_dependency "json", "> 0"
|
15
|
+
gem.add_dependency "curb", "> 0"
|
16
|
+
gem.add_dependency "facets", "> 0"
|
17
|
+
gem.add_dependency "uuid", "> 0"
|
18
|
+
gem.rubyforge_project = "flareshow"
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
22
|
+
end
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
Rake::TestTask.new(:test) do |test|
|
26
|
+
test.libs << 'lib' << 'test'
|
27
|
+
test.pattern = 'test/**/*_test.rb'
|
28
|
+
test.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
begin
|
32
|
+
require 'rcov/rcovtask'
|
33
|
+
Rcov::RcovTask.new do |test|
|
34
|
+
test.libs << 'test'
|
35
|
+
test.pattern = 'test/**/*_test.rb'
|
36
|
+
test.verbose = true
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
task :rcov do
|
40
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
task :test => :check_dependencies
|
45
|
+
|
46
|
+
task :default => :test
|
47
|
+
|
48
|
+
require 'rake/rdoctask'
|
49
|
+
Rake::RDocTask.new do |rdoc|
|
50
|
+
if File.exist?('VERSION')
|
51
|
+
version = File.read('VERSION')
|
52
|
+
else
|
53
|
+
version = ""
|
54
|
+
end
|
55
|
+
|
56
|
+
rdoc.rdoc_dir = 'rdoc'
|
57
|
+
rdoc.title = "flareshow #{version}"
|
58
|
+
rdoc.rdoc_files.include('README*')
|
59
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
60
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
TODO:
|
2
|
+
shareflow api docs
|
3
|
+
write tests with Fakeweb
|
4
|
+
flesh out more resource methods
|
5
|
+
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
|
6
|
+
namespaced objects
|
7
|
+
handle failure states on requests
|
8
|
+
namespace auth requests to be consistent with other api calls
|
9
|
+
|
10
|
+
TODONE:
|
11
|
+
remove temporary auth setup logging in user automatically
|
12
|
+
|
13
|
+
QUESTIONS:
|
14
|
+
should authentication responses look like query and commit responses namespacing is applied differently in authentication currently?
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.1
|
data/lib/cache.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# provides an interface for various
|
2
|
+
# caches that flareshow might use
|
3
|
+
class Flareshow::CacheManager
|
4
|
+
|
5
|
+
class << self
|
6
|
+
# assimilate the resources provided in the response
|
7
|
+
def assimilate_resources(data)
|
8
|
+
# process each resource key and generate a new object
|
9
|
+
# or merge the object data with an existing object
|
10
|
+
data.inject({}) do |memo,resource_pair|
|
11
|
+
resource_key, resources = resource_pair[0], resource_pair[1]
|
12
|
+
|
13
|
+
fs_resource_array = memo[resource_key] ||= []
|
14
|
+
klass_name = Flareshow::ResourceToClassMap[resource_key]
|
15
|
+
klass = Kernel.const_get(klass_name)
|
16
|
+
if klass_name
|
17
|
+
if klass
|
18
|
+
resources.each do |resource_data|
|
19
|
+
item = cache.get_resource(resource_key, resource_data["id"])
|
20
|
+
if item
|
21
|
+
item.update(resource_data, :server)
|
22
|
+
else
|
23
|
+
item = klass.new(resource_data, :server)
|
24
|
+
end
|
25
|
+
cache.set_resource(resource_key, item.id, item)
|
26
|
+
fs_resource_array << item
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
memo
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# get the managed cache object
|
35
|
+
def cache
|
36
|
+
@cache ||= Flareshow::Cache.new
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
# a simple in memory cache for Flareshow objects
|
45
|
+
class Flareshow::Cache
|
46
|
+
|
47
|
+
# you can create your own cache object and plug it into the cache manager.
|
48
|
+
# The cache class should implement the public methods
|
49
|
+
# get_resource, set_resource, delete_resource, list_resource, flush and size
|
50
|
+
|
51
|
+
# load a resource from the cache
|
52
|
+
def get_resource(resource_key, id)
|
53
|
+
resource_cache(resource_key)[id]
|
54
|
+
end
|
55
|
+
|
56
|
+
# set a resource in the cache
|
57
|
+
def set_resource(resource_key, id, object)
|
58
|
+
resource_cache(resource_key)[id] = object
|
59
|
+
end
|
60
|
+
|
61
|
+
# remove a resource
|
62
|
+
def delete_resource(resource_key, id)
|
63
|
+
resource_cache(resource_key).delete(id)
|
64
|
+
end
|
65
|
+
|
66
|
+
def list_resource(resource_key)
|
67
|
+
resource_cache(resource_key)
|
68
|
+
end
|
69
|
+
|
70
|
+
# remove all cached objects
|
71
|
+
def flush
|
72
|
+
data = {}
|
73
|
+
end
|
74
|
+
|
75
|
+
# number of cached objects
|
76
|
+
def size
|
77
|
+
data.values.inject(0){|m,v| m+=v.size}
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
# data store for the cache
|
82
|
+
def data
|
83
|
+
@cache ||= {}
|
84
|
+
end
|
85
|
+
|
86
|
+
# get a specific resource dictionary
|
87
|
+
def resource_cache(resource_key)
|
88
|
+
data[resource_key] ||= Dictionary.new
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
data/lib/comment.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
class Comment < Flareshow::Resource
|
2
|
+
|
3
|
+
@attr_accessible = [:content, :post_id]
|
4
|
+
@attr_required = [:post_id, :content]
|
5
|
+
|
6
|
+
extend Flareshow::Searchable
|
7
|
+
|
8
|
+
# permalink to this comment
|
9
|
+
def permalink(mobile=false)
|
10
|
+
if mobile
|
11
|
+
"http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/mobile/post/#{reply_to}"
|
12
|
+
else
|
13
|
+
"http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/p/#{reply_to}?comment_id#{id}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# get the post for this comment
|
18
|
+
def post
|
19
|
+
Post.first(:id => post_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
# user for this post
|
23
|
+
def user
|
24
|
+
return User.current unless user_id
|
25
|
+
User.first({:id => user_id})
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/lib/exceptions.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
module Flareshow
|
2
|
+
|
3
|
+
class MissingRequiredField < Exception
|
4
|
+
def message
|
5
|
+
"you attempted to save an object without providing all of the required fields"
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
class APIAccessException < Exception
|
10
|
+
def message
|
11
|
+
"you've attempted to change an object in a way not permitted by the API"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class ConfigurationException < Exception
|
16
|
+
def message
|
17
|
+
"the shareflow service connection has not been configured properly"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class AuthenticationRequired < Exception
|
22
|
+
def message
|
23
|
+
"this action requires authentication"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class AuthenticationFailed < Exception
|
28
|
+
def message
|
29
|
+
"authentication failed"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class FileAttachment < Flareshow::Resource
|
2
|
+
|
3
|
+
@read_only=true
|
4
|
+
|
5
|
+
extend Flareshow::Searchable
|
6
|
+
|
7
|
+
# =================
|
8
|
+
# = Class Methods =
|
9
|
+
# =================
|
10
|
+
class << self
|
11
|
+
# file attachments has a resource key of files
|
12
|
+
# for querying the server
|
13
|
+
def resource_key
|
14
|
+
"files"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# download the file contents
|
19
|
+
def download
|
20
|
+
url = self.url
|
21
|
+
unless url.match(/http/)
|
22
|
+
url = "http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}#{url}"
|
23
|
+
end
|
24
|
+
Flareshow::Util.log_info("getting #{url}")
|
25
|
+
Flareshow::Service.http_get(url)
|
26
|
+
end
|
27
|
+
|
28
|
+
# post for this file
|
29
|
+
def post
|
30
|
+
return false unless post_id
|
31
|
+
Post.find({:id => post_id})
|
32
|
+
end
|
33
|
+
|
34
|
+
# get the user for this file
|
35
|
+
def user
|
36
|
+
p = post && post.first
|
37
|
+
p.user && p.user.first
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/lib/flareshow.rb
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
ROOT = File.dirname(__FILE__) unless defined? ROOT
|
2
|
+
|
3
|
+
# gems
|
4
|
+
require 'rubygems' #TODO fix
|
5
|
+
require 'json'
|
6
|
+
require 'facets'
|
7
|
+
require 'facets/dictionary'
|
8
|
+
require 'uuid'
|
9
|
+
require 'mime/types'
|
10
|
+
require 'cgi'
|
11
|
+
|
12
|
+
# std lib
|
13
|
+
require 'net/http'
|
14
|
+
require 'net/https'
|
15
|
+
require 'ostruct'
|
16
|
+
require 'yaml'
|
17
|
+
require 'logger'
|
18
|
+
require 'ruby-debug'
|
19
|
+
|
20
|
+
# Application Constants and configuration
|
21
|
+
module Flareshow
|
22
|
+
|
23
|
+
# mappings to allow easy conversion from the
|
24
|
+
# response keys the server sends back in JSUP
|
25
|
+
# messages
|
26
|
+
ResourceToClassMap = {
|
27
|
+
"flows" => "Flow",
|
28
|
+
"posts" => "Post",
|
29
|
+
"comments" => "Comment",
|
30
|
+
"files" => "FileAttachment",
|
31
|
+
"memberships" => "Membership",
|
32
|
+
"invitations" => "Invitation",
|
33
|
+
"users" => "User"
|
34
|
+
} unless defined? ResourceToClassMap
|
35
|
+
ClassToResourceMap = ResourceToClassMap.invert unless defined? ClassToResourceMap
|
36
|
+
end
|
37
|
+
|
38
|
+
# app
|
39
|
+
require File.join(ROOT, 'service')
|
40
|
+
require File.join(ROOT, 'resource')
|
41
|
+
require File.join(ROOT, 'cache')
|
42
|
+
require File.join(ROOT, 'searchable')
|
43
|
+
|
44
|
+
# logging
|
45
|
+
DEFAULT_LOGGER = Logger.new(STDOUT) unless defined?(DEFAULT_LOGGER)
|
46
|
+
DEFAULT_LOGGER.level = Logger::ERROR
|
47
|
+
Dir.glob(File.join(ROOT, "*.rb")).each{|lib| require lib}
|
48
|
+
|
49
|
+
# check for presence of config file
|
50
|
+
config_file_path = File.expand_path("~/.flareshowrc")
|
51
|
+
if File.exists?(config_file_path) && !Flareshow::Service.authenticated?
|
52
|
+
data = YAML.load_file(config_file_path)
|
53
|
+
Flareshow::Service.debug_output=true if data["debug_http"]
|
54
|
+
host = data["host"] || "biz.zenbe.com"
|
55
|
+
subdomain = data["subdomain"]
|
56
|
+
DEFAULT_LOGGER.level = data["log_level"].to_i if data["log_level"]
|
57
|
+
Flareshow::Service.configure(subdomain, host)
|
58
|
+
if data["login"] && data["password"]
|
59
|
+
User.log_in(data["login"], data["password"])
|
60
|
+
end
|
61
|
+
end
|
data/lib/flow.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
class Flow < Flareshow::Resource
|
2
|
+
|
3
|
+
@attr_accessible = [:name, :remove_members, :uninvite, :invite]
|
4
|
+
@attr_required = [:name]
|
5
|
+
|
6
|
+
# =================
|
7
|
+
# = Class Methods =
|
8
|
+
# =================
|
9
|
+
class << self
|
10
|
+
# find a flow by name
|
11
|
+
def find_by_name(name)
|
12
|
+
self.first({:name => name})
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# permalink for this flow
|
17
|
+
def permalink(mobile=false)
|
18
|
+
if mobile
|
19
|
+
"http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/mobile/flows/#{id}"
|
20
|
+
else
|
21
|
+
"http://#{Flareshow::Service.server.host}/#{Flareshow::Service.server.domain}/shareflow/c/#{id}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
#invite/reinvite a user to a flow by email address
|
26
|
+
def send_invitations(email_addresses)
|
27
|
+
self.invite = [email_addresses].flatten
|
28
|
+
self.save
|
29
|
+
end
|
30
|
+
|
31
|
+
# uninvite an invited user from a flow by email address
|
32
|
+
def revoke_invitations(email_addresses)
|
33
|
+
self.uninvite = [email_addresses].flatten
|
34
|
+
self.save
|
35
|
+
end
|
36
|
+
|
37
|
+
# remove a user from a flow
|
38
|
+
# you must be the owner of the flow to perform
|
39
|
+
# this action
|
40
|
+
def remove_members(member_ids)
|
41
|
+
self.remove_members = [member_ids].flatten
|
42
|
+
self.save
|
43
|
+
end
|
44
|
+
|
45
|
+
# build a new post but don't persist it immediatel
|
46
|
+
def build_post(attributes)
|
47
|
+
post = Post.new
|
48
|
+
post.update(attributes)
|
49
|
+
post.flow_id = id
|
50
|
+
post
|
51
|
+
end
|
52
|
+
|
53
|
+
# create a new post in this flow
|
54
|
+
def create_post(attributes)
|
55
|
+
p=build_post(attributes)
|
56
|
+
p.save
|
57
|
+
end
|
58
|
+
|
59
|
+
# posts for this flow...only returns the first 100 (API max)
|
60
|
+
# to load all posts you can interact with the Service class directly
|
61
|
+
# to loop through in batches of 100 using the offset parameter or
|
62
|
+
# create a flow object and override this method with the looping logic
|
63
|
+
def posts
|
64
|
+
Post.find(:flow_id => id)
|
65
|
+
end
|
66
|
+
|
67
|
+
# list the invitations to this flow
|
68
|
+
def list_invitations
|
69
|
+
Invitation.find(:flow_id => id)
|
70
|
+
end
|
71
|
+
|
72
|
+
# list all users on the flow currently
|
73
|
+
def list_users
|
74
|
+
response = Flareshow::Service.query({:flows=>{:id => self.id, :limit => 1, :include=>['users']}})
|
75
|
+
(Flareshow::CacheManager.assimilate_resources(response["resources"]) || {})["users"]
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
@@ -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
|