bitballoon 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +4 -0
- data/Gemfile.lock +43 -0
- data/LICENSE.txt +22 -0
- data/README.md +130 -0
- data/Rakefile +7 -0
- data/bin/bitballoon +45 -0
- data/bitballoon.gemspec +25 -0
- data/lib/bitballoon.rb +13 -0
- data/lib/bitballoon/client.rb +49 -0
- data/lib/bitballoon/collection_proxy.rb +43 -0
- data/lib/bitballoon/file.rb +7 -0
- data/lib/bitballoon/files.rb +7 -0
- data/lib/bitballoon/form.rb +9 -0
- data/lib/bitballoon/forms.rb +7 -0
- data/lib/bitballoon/model.rb +53 -0
- data/lib/bitballoon/site.rb +63 -0
- data/lib/bitballoon/sites.rb +36 -0
- data/lib/bitballoon/submission.rb +6 -0
- data/lib/bitballoon/submissions.rb +7 -0
- data/lib/bitballoon/version.rb +3 -0
- data/test/client_test.rb +73 -0
- data/test/files/site-dir.zip +0 -0
- data/test/files/site-dir/index.html +5 -0
- data/test/sites_test.rb +52 -0
- data/test/test_helper.rb +6 -0
- metadata +157 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
bitballoon (0.0.2)
|
5
|
+
highline
|
6
|
+
oauth2 (>= 0.9.2)
|
7
|
+
slop
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
addressable (2.3.3)
|
13
|
+
crack (0.3.2)
|
14
|
+
faraday (0.8.8)
|
15
|
+
multipart-post (~> 1.2.0)
|
16
|
+
highline (1.6.14)
|
17
|
+
httpauth (0.2.0)
|
18
|
+
jwt (0.1.8)
|
19
|
+
multi_json (>= 1.5)
|
20
|
+
minitest (5.0.8)
|
21
|
+
multi_json (1.8.0)
|
22
|
+
multi_xml (0.5.5)
|
23
|
+
multipart-post (1.2.0)
|
24
|
+
oauth2 (0.9.2)
|
25
|
+
faraday (~> 0.8)
|
26
|
+
httpauth (~> 0.2)
|
27
|
+
jwt (~> 0.1.4)
|
28
|
+
multi_json (~> 1.0)
|
29
|
+
multi_xml (~> 0.5)
|
30
|
+
rack (~> 1.2)
|
31
|
+
rack (1.5.2)
|
32
|
+
slop (3.4.3)
|
33
|
+
webmock (1.11.0)
|
34
|
+
addressable (>= 2.2.7)
|
35
|
+
crack (>= 0.3.2)
|
36
|
+
|
37
|
+
PLATFORMS
|
38
|
+
ruby
|
39
|
+
|
40
|
+
DEPENDENCIES
|
41
|
+
bitballoon!
|
42
|
+
minitest
|
43
|
+
webmock
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Mathias Biilmann Christensen
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
BitBalloon Ruby Client
|
2
|
+
======================
|
3
|
+
|
4
|
+
BitBalloon is a hosting service for the programmable web. It understands your documents, processes forms and lets you do deploys, manage forms submissions, inject javascript snippets into sites and do intelligent updates of HTML documents through it's API.
|
5
|
+
|
6
|
+
Installation
|
7
|
+
============
|
8
|
+
|
9
|
+
Install the gem by running
|
10
|
+
|
11
|
+
gem install bitballoon
|
12
|
+
|
13
|
+
or put it in a Gemfile and run `bundle install`
|
14
|
+
|
15
|
+
gem bitballoon
|
16
|
+
|
17
|
+
|
18
|
+
Authenticating
|
19
|
+
==============
|
20
|
+
|
21
|
+
You'll need an application client id and a client secret before you can access the BitBalloon API. Please contact us at team@bitballoon.com for your credentials.
|
22
|
+
|
23
|
+
Once you have your credentials you can instantiate a BitBalloon client.
|
24
|
+
|
25
|
+
bitballoon = BitBalloon::Client.new(:client_id => "YOUR_API_KEY", :client_secret => "YOUR_API_SECRET")
|
26
|
+
|
27
|
+
Before you can make any requests to the API, you'll need to authenticate with OAuth2. The BitBalloon client supports two OAuth2 flows.
|
28
|
+
|
29
|
+
If you're authenticating on behalf of a user, you'll need to get a valid access token for that user. Use the BitBalloon client to request an authentication URL:
|
30
|
+
|
31
|
+
url = bitballoon.authorize_url(:redirect_uri => "http://www.example.com/callback")
|
32
|
+
|
33
|
+
The user then visits that URL and will be prompted to authorize your application to access his BitBalloon sites. If she grants permission, she'll be redirected back to the `redirect_uri` provided in the `authorize_url` call. This URL must match the redirect url configured for your BitBalloon application. Once the user comes back to your app, you'll be able to access a `code` query parameter that gives you an authorization code. Use this to finish the OAuth2 flow:
|
34
|
+
|
35
|
+
bitballoon.authorize!(token, :redirect_uri => "http://www.example.com/callback")
|
36
|
+
|
37
|
+
|
38
|
+
Sites
|
39
|
+
=====
|
40
|
+
|
41
|
+
Getting a list of all sites you have access to:
|
42
|
+
|
43
|
+
bitballoon.sites.each do |site|
|
44
|
+
puts site.url
|
45
|
+
end
|
46
|
+
|
47
|
+
Getting a specific site by id:
|
48
|
+
|
49
|
+
site = bitballoon.sites.get(id)
|
50
|
+
|
51
|
+
Creating a site from a directory:
|
52
|
+
|
53
|
+
site = bitballoon.sites.create(:dir => "/tmp/my-site")
|
54
|
+
|
55
|
+
Creating a site from a zip file:
|
56
|
+
|
57
|
+
site = bitballoon.sites.create(:zip => "/tmp/my-site.zip")
|
58
|
+
|
59
|
+
Both methods will create the site and upload the files. The site will then be processing.
|
60
|
+
|
61
|
+
site.state == "processing"
|
62
|
+
site.processing? == true
|
63
|
+
|
64
|
+
Refresh a site to update the state:
|
65
|
+
|
66
|
+
site.refresh
|
67
|
+
|
68
|
+
Use `wait_until_ready` to wait until a site has finished processing.
|
69
|
+
|
70
|
+
site = bitballoon.sites.create(:dir => "/tmp/my-site")
|
71
|
+
site.wait_for_ready
|
72
|
+
site.state == "ready"
|
73
|
+
|
74
|
+
Update the name of the site (its subdomain), the custom domain and the notification email for form submissions:
|
75
|
+
|
76
|
+
site.update(:subdomain => "my-site", :custom_domain => "www.example.com", :notification_email => "me@example.com")
|
77
|
+
|
78
|
+
Deleting a site:
|
79
|
+
|
80
|
+
site.destroy!
|
81
|
+
|
82
|
+
Forms
|
83
|
+
=====
|
84
|
+
|
85
|
+
Access all forms you have access to:
|
86
|
+
|
87
|
+
bitballoon.forms
|
88
|
+
|
89
|
+
Access forms for a specific site:
|
90
|
+
|
91
|
+
site = bitballoon.sites.get(id)
|
92
|
+
site.forms
|
93
|
+
|
94
|
+
Access a specific form:
|
95
|
+
|
96
|
+
form = bitballoon.forms.get(id)
|
97
|
+
|
98
|
+
Access a list of all form submissions you have access to:
|
99
|
+
|
100
|
+
bitballoon.submissions
|
101
|
+
|
102
|
+
Access submissions from a specific site
|
103
|
+
|
104
|
+
site = bitballoon.sites.get(id)
|
105
|
+
site.submissions
|
106
|
+
|
107
|
+
Access submissions from a specific form
|
108
|
+
|
109
|
+
form = bitballoon.forms.get(id)
|
110
|
+
form.submissions
|
111
|
+
|
112
|
+
Get a specific submission
|
113
|
+
|
114
|
+
bitballoon.submissions.get(id)
|
115
|
+
|
116
|
+
Files
|
117
|
+
=====
|
118
|
+
|
119
|
+
Access all files in a site:
|
120
|
+
|
121
|
+
site = bitballoon.sites.get(id)
|
122
|
+
site.files
|
123
|
+
|
124
|
+
Get a specific file:
|
125
|
+
|
126
|
+
file = site.files.get(path) # Example paths: "/css/main.css", "/index.html"
|
127
|
+
|
128
|
+
Reading a file:
|
129
|
+
|
130
|
+
file.read
|
data/Rakefile
ADDED
data/bin/bitballoon
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'slop'
|
4
|
+
require 'bitballoon'
|
5
|
+
require 'highline/import'
|
6
|
+
|
7
|
+
opts = Slop.parse do
|
8
|
+
on '-v', 'Print the version' do
|
9
|
+
puts "Version #{BitBalloon::VERSION}"
|
10
|
+
end
|
11
|
+
|
12
|
+
command 'deploy' do
|
13
|
+
run do |opts, args|
|
14
|
+
path = args.first ? File.expand_path(args.first) : Dir.getwd
|
15
|
+
|
16
|
+
raise "File or dir doesn't exist: #{path}" unless File.exist?(path)
|
17
|
+
raise "Can't deploy a single file" if File.file?(path) && !path.match(/\.zip$/)
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
credentials_path = File.exist?(File.expand_path(".bitballoon")) ? File.expand_path(".bitballoon") : "#{Dir.home}/.bitballoon"
|
22
|
+
if File.exist?(credentials_path)
|
23
|
+
access_token = JSON.parse(File.read(credentials_path))['access_token']
|
24
|
+
client = BitBalloon::Client.new(:access_token => access_token)
|
25
|
+
else
|
26
|
+
puts "Please enter your BitBalloon API Credentials (if you don't have any, you can create your credentials at https://www.bitballoon.com/applications)"
|
27
|
+
client_id = ask("Client ID:")
|
28
|
+
client_secret = ask("Client Secret:")
|
29
|
+
client = BitBalloon::Client.new(:client_id => client_id, :client_secret => client_secret)
|
30
|
+
client.authorize_from_credentials!
|
31
|
+
File.open(credentials_path, "w") do |file|
|
32
|
+
file.write(JSON.generate(:access_token => client.access_token))
|
33
|
+
end
|
34
|
+
puts "Wrote access token to '#{credentials_path}'"
|
35
|
+
end
|
36
|
+
|
37
|
+
site = path.match(/\.zip$/) ? client.sites.create(:zip => path) : client.sites.create(:dir => path)
|
38
|
+
puts "Waiting for processing"
|
39
|
+
site.wait_for_ready do |site|
|
40
|
+
puts "Polling site: #{site.id} - #{site.state}"
|
41
|
+
end
|
42
|
+
puts "Site deployed: #{site.url}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/bitballoon.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bitballoon/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "bitballoon"
|
8
|
+
gem.version = BitBalloon::VERSION
|
9
|
+
gem.authors = ["Mathias Biilmann Christensen"]
|
10
|
+
gem.email = ["mathias@bitballoon.com"]
|
11
|
+
gem.description = %q{API Client for BitBalloon}
|
12
|
+
gem.summary = %q{API Client for BitBalloon}
|
13
|
+
gem.homepage = "https://www.bitballoon.com"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency "oauth2", ">= 0.9.2"
|
21
|
+
gem.add_dependency "slop"
|
22
|
+
gem.add_dependency "highline"
|
23
|
+
gem.add_development_dependency "minitest"
|
24
|
+
gem.add_development_dependency "webmock"
|
25
|
+
end
|
data/lib/bitballoon.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require "json"
|
2
|
+
require "bitballoon/version"
|
3
|
+
require "bitballoon/client"
|
4
|
+
require "bitballoon/collection_proxy"
|
5
|
+
require "bitballoon/model"
|
6
|
+
require "bitballoon/sites"
|
7
|
+
require "bitballoon/forms"
|
8
|
+
require "bitballoon/submissions"
|
9
|
+
require "bitballoon/files"
|
10
|
+
|
11
|
+
module BitBalloon
|
12
|
+
# Your code goes here...
|
13
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'oauth2'
|
2
|
+
|
3
|
+
module BitBalloon
|
4
|
+
class Client
|
5
|
+
ENDPOINT = ENV['OAUTH_CLIENT_API_URL'] || 'https://www.bitballoon.com'
|
6
|
+
API_VERSION = "v1"
|
7
|
+
|
8
|
+
attr_accessor :client_id, :client_secret, :oauth, :access_token
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
self.client_id = options[:client_id]
|
12
|
+
self.client_secret = options[:client_secret]
|
13
|
+
self.access_token = options[:access_token]
|
14
|
+
self.oauth = OAuth2::Client.new(client_id, client_secret, :site => ENDPOINT, :connection_build => lambda {|f|
|
15
|
+
f.request :multipart
|
16
|
+
f.request :url_encoded
|
17
|
+
f.adapter :net_http
|
18
|
+
})
|
19
|
+
end
|
20
|
+
|
21
|
+
def authorize_url(options)
|
22
|
+
oauth.auth_code.authorize_url(options)
|
23
|
+
end
|
24
|
+
|
25
|
+
def authorize_from_code!(authorization_code, options)
|
26
|
+
@oauth_token = oauth.auth_code.get_token(authorization_code, options)
|
27
|
+
self.access_token = oauth_token.token
|
28
|
+
end
|
29
|
+
|
30
|
+
def authorize_from_credentials!
|
31
|
+
@oauth_token = oauth.client_credentials.get_token
|
32
|
+
self.access_token = oauth_token.token
|
33
|
+
end
|
34
|
+
|
35
|
+
def sites
|
36
|
+
Sites.new(self)
|
37
|
+
end
|
38
|
+
|
39
|
+
def request(verb, path, opts={}, &block)
|
40
|
+
raise "Authorize with BitBalloon before making requests" unless oauth_token
|
41
|
+
oauth_token.request(verb, ::File.join("/api", API_VERSION, path), opts, &block)
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def oauth_token
|
46
|
+
@oauth_token ||= access_token && OAuth2::AccessToken.new(oauth, access_token)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module BitBalloon
|
2
|
+
class CollectionProxy
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_accessor :client, :prefix
|
6
|
+
|
7
|
+
def self.path(value = nil)
|
8
|
+
return @path unless value
|
9
|
+
@path = value
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.model(value = nil)
|
13
|
+
@model ||= BitBalloon.const_get(to_s.split("::").last.sub(/s$/, ''))
|
14
|
+
end
|
15
|
+
|
16
|
+
def initialize(client, prefix = nil)
|
17
|
+
self.client = client
|
18
|
+
self.prefix = prefix
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
response = client.request(:get, [prefix, path].compact.join("/"))
|
23
|
+
response.parsed.map {|attributes| model.new(client, attributes) } if response.parsed
|
24
|
+
end
|
25
|
+
|
26
|
+
def each(&block)
|
27
|
+
all.each(&block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(id)
|
31
|
+
response = client.request(:get, ::File.join(path, id))
|
32
|
+
model.new(client, response.parsed) if response.parsed
|
33
|
+
end
|
34
|
+
|
35
|
+
def model
|
36
|
+
self.class.model
|
37
|
+
end
|
38
|
+
|
39
|
+
def path
|
40
|
+
self.class.path
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module BitBalloon
|
2
|
+
class Model
|
3
|
+
attr_reader :client
|
4
|
+
|
5
|
+
def self.fields(*names)
|
6
|
+
return @fields if names.empty?
|
7
|
+
|
8
|
+
@fields ||= []
|
9
|
+
|
10
|
+
names.each do |name|
|
11
|
+
define_method name do
|
12
|
+
@attributes[name.to_sym]
|
13
|
+
end
|
14
|
+
|
15
|
+
define_method "#{name}=" do |value|
|
16
|
+
@attributes[name.to_sym] = value
|
17
|
+
end
|
18
|
+
|
19
|
+
@fields.push(name.to_sym)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.collection(value = nil)
|
24
|
+
@collection ||= BitBalloon.const_get(to_s.split("::").last + "s")
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(client, attributes)
|
28
|
+
@client = client
|
29
|
+
@attributes = {}
|
30
|
+
process(attributes)
|
31
|
+
end
|
32
|
+
|
33
|
+
def process(attributes)
|
34
|
+
self.class.fields.each do |field|
|
35
|
+
@attributes[field] = attributes[field] || attributes[field.to_s]
|
36
|
+
end
|
37
|
+
self
|
38
|
+
end
|
39
|
+
|
40
|
+
def refresh
|
41
|
+
response = client.request(:get, path)
|
42
|
+
process(response.parsed)
|
43
|
+
end
|
44
|
+
|
45
|
+
def collection
|
46
|
+
self.class.collection
|
47
|
+
end
|
48
|
+
|
49
|
+
def path
|
50
|
+
::File.join(collection.path, id)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'digest/sha1'
|
2
|
+
|
3
|
+
module BitBalloon
|
4
|
+
class Site < Model
|
5
|
+
fields :id, :state, :premium, :claimed, :name, :custom_domain, :url,
|
6
|
+
:admin_url, :screenshot_url, :created_at, :updated_at, :user_id,
|
7
|
+
:required
|
8
|
+
|
9
|
+
def upload_dir(dir)
|
10
|
+
return unless state == "uploading"
|
11
|
+
|
12
|
+
shas = {}
|
13
|
+
Dir[::File.join(dir, "**", "*")].each do |file|
|
14
|
+
next unless ::File.file?(file)
|
15
|
+
pathname = ::File.join("/", file[dir.length..-1])
|
16
|
+
next if pathname.match(/(^\/?__MACOSX\/|\/\.)/)
|
17
|
+
shas[Digest::SHA1.hexdigest(::File.read(file))] = pathname
|
18
|
+
end
|
19
|
+
|
20
|
+
(required || []).each do |sha|
|
21
|
+
client.request(:put, ::File.join(path, "files", shas[sha]), :body => ::File.read(::File.join(dir, shas[sha])))
|
22
|
+
end
|
23
|
+
|
24
|
+
refresh
|
25
|
+
end
|
26
|
+
|
27
|
+
def ready?
|
28
|
+
state == "ready"
|
29
|
+
end
|
30
|
+
|
31
|
+
def wait_for_ready(timeout = 900)
|
32
|
+
start = Time.now
|
33
|
+
while !ready?
|
34
|
+
sleep 5
|
35
|
+
refresh
|
36
|
+
yield(self) if block_given?
|
37
|
+
raise "Timeout while waiting for ready" if Time.now - start > timeout
|
38
|
+
end
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def update(attributes)
|
43
|
+
raise "Not implemented yet"
|
44
|
+
end
|
45
|
+
|
46
|
+
def destroy!
|
47
|
+
client.request(:delete, path)
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
def forms
|
52
|
+
Forms.new(client, path)
|
53
|
+
end
|
54
|
+
|
55
|
+
def submissions
|
56
|
+
Submissions.new(client, path)
|
57
|
+
end
|
58
|
+
|
59
|
+
def files
|
60
|
+
Files.new(client, path)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "bitballoon/site"
|
2
|
+
require "digest/sha1"
|
3
|
+
|
4
|
+
module BitBalloon
|
5
|
+
class Sites < CollectionProxy
|
6
|
+
path "/sites"
|
7
|
+
|
8
|
+
def create(attributes = {})
|
9
|
+
if attributes[:dir]
|
10
|
+
dir = attributes[:dir]
|
11
|
+
response = client.request(:post, "/sites", :body => JSON.generate({:files => inventory(dir)}), :headers => {"Content-Type" => "application/json"})
|
12
|
+
Site.new(client, response.parsed).tap do |site|
|
13
|
+
site.upload_dir(dir)
|
14
|
+
end
|
15
|
+
elsif attributes[:zip]
|
16
|
+
::File.open(attributes[:zip]) do |file|
|
17
|
+
response = client.request(:post, "/sites", :body => {
|
18
|
+
:zip => Faraday::UploadIO.new(file, 'application/zip')
|
19
|
+
})
|
20
|
+
Site.new(client, response.parsed)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
def inventory(dir)
|
27
|
+
files = {}
|
28
|
+
Dir[::File.join(dir, "**", "*")].each do |file|
|
29
|
+
next unless ::File.file?(file)
|
30
|
+
path = ::File.join("/", file[dir.length..-1])
|
31
|
+
files[path] = Digest::SHA1.hexdigest(::File.read(file))
|
32
|
+
end
|
33
|
+
files
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/test/client_test.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class ClientTest < MiniTest::Unit::TestCase
|
4
|
+
attr_reader :client
|
5
|
+
|
6
|
+
def setup
|
7
|
+
@client = BitBalloon::Client.new(:client_id => "client_id", :client_secret => "client_secret")
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_authorize_url
|
11
|
+
expected = "https://www.bitballoon.com/oauth/authorize?response_type=code&client_id=client_id&redirect_uri=http%3A%2F%2Fexample.com%2Fcallback"
|
12
|
+
assert_equal expected, client.authorize_url(:redirect_uri => "http://example.com/callback")
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_authorize_from_code
|
16
|
+
stub_request(:post, "https://www.bitballoon.com/oauth/token").to_return(
|
17
|
+
:headers => {'Content-Type' => 'application/json'},
|
18
|
+
:body => {
|
19
|
+
"access_token" => "2YotnFZFEjr1zCsicMWpAA"
|
20
|
+
})
|
21
|
+
client.authorize_from_code!("authorization_code", :redirect_uri => "http://example.com/callback")
|
22
|
+
assert_equal "2YotnFZFEjr1zCsicMWpAA", client.access_token
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_authorize_from_credentials
|
26
|
+
stub_request(:post, "https://client_id:client_secret@www.bitballoon.com/oauth/token").to_return(
|
27
|
+
:headers => {'Content-Type' => 'application/json'},
|
28
|
+
:body => {
|
29
|
+
"access_token" => "2YotnFZFEjr1zCsicMWpAA"
|
30
|
+
})
|
31
|
+
|
32
|
+
client.authorize_from_credentials!
|
33
|
+
assert_equal "2YotnFZFEjr1zCsicMWpAA", client.access_token
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_simple_get_request
|
37
|
+
stub_request(:get, "https://www.bitballoon.com/api/v1/sites")
|
38
|
+
.with(:headers => {'Authorization' => "Bearer access_token"})
|
39
|
+
.to_return(
|
40
|
+
:headers => {'Content-Type' => 'application/json'},
|
41
|
+
:body => []
|
42
|
+
)
|
43
|
+
|
44
|
+
client.access_token = "access_token"
|
45
|
+
response = client.request(:get, "/sites")
|
46
|
+
assert_equal [], response.parsed
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_sites
|
50
|
+
stub_request(:get, "https://www.bitballoon.com/api/v1/sites")
|
51
|
+
.with(:headers => {'Authorization' => "Bearer access_token"})
|
52
|
+
.to_return(
|
53
|
+
:headers => {'Content-Type' => 'application/json'},
|
54
|
+
:body => JSON.generate([{:url => "http://www.example.com"}])
|
55
|
+
)
|
56
|
+
client.access_token = "access_token"
|
57
|
+
sites = client.sites.all
|
58
|
+
assert_equal "http://www.example.com", sites.first.url
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_get_site
|
62
|
+
stub_request(:get, "https://www.bitballoon.com/api/v1/sites/1234")
|
63
|
+
.with(:headers => {'Authorization' => "Bearer access_token"})
|
64
|
+
.to_return(
|
65
|
+
:headers => {'Content-Type' => 'application/json'},
|
66
|
+
:body => {:url => "http://www.example.com"}
|
67
|
+
)
|
68
|
+
|
69
|
+
client.access_token = "access_token"
|
70
|
+
site = client.sites.get("1234")
|
71
|
+
assert_equal "http://www.example.com", site.url
|
72
|
+
end
|
73
|
+
end
|
Binary file
|
data/test/sites_test.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'digest/sha1'
|
3
|
+
|
4
|
+
class SitesTest < MiniTest::Unit::TestCase
|
5
|
+
attr_reader :client
|
6
|
+
attr_accessor :_assertions
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@client = BitBalloon::Client.new(:client_id => "client_id", :client_secret => "client_secret")
|
10
|
+
@client.access_token = "access_token"
|
11
|
+
self._assertions = 0
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_create_from_dir
|
15
|
+
body = nil
|
16
|
+
dir = ::File.expand_path("../files/site-dir", __FILE__)
|
17
|
+
index_sha = Digest::SHA1.hexdigest(::File.read(::File.join(dir, "index.html")))
|
18
|
+
|
19
|
+
stub_request(:post, "https://www.bitballoon.com/api/v1/sites")
|
20
|
+
.to_return {|request|
|
21
|
+
body = JSON.parse(request.body)
|
22
|
+
{
|
23
|
+
:headers => {'Content-Type' => 'application/json'},
|
24
|
+
:body => JSON.generate({:id => "1234", :state => "uploading", :required => [index_sha]})
|
25
|
+
}
|
26
|
+
}
|
27
|
+
stub_request(:put, "https://www.bitballoon.com/api/v1/sites/1234/files/index.html")
|
28
|
+
stub_request(:get, "https://www.bitballoon.com/api/v1/sites/1234")
|
29
|
+
.to_return(:headers => {'Content-Type' => 'application/json'}, :body => {:id => "1234", :state => "processing"})
|
30
|
+
|
31
|
+
site = client.sites.create(:dir => dir)
|
32
|
+
|
33
|
+
assert_equal 'processing', site.state
|
34
|
+
assert_equal index_sha, body['files']['/index.html']
|
35
|
+
|
36
|
+
assert_requested :put, "https://www.bitballoon.com/api/v1/sites/1234/files/index.html",
|
37
|
+
:body => ::File.read(::File.join(dir, "index.html")), :times => 1 # ===> Success
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_create_from_zip
|
41
|
+
stub_request(:post, "https://www.bitballoon.com/api/v1/sites")
|
42
|
+
.to_return({
|
43
|
+
:headers => {'Content-Type' => 'application/json'},
|
44
|
+
:body => JSON.generate({:id => "1234", :state => "processing", :required => []})
|
45
|
+
})
|
46
|
+
|
47
|
+
zip = ::File.expand_path("../files/site-dir.zip", __FILE__)
|
48
|
+
site = client.sites.create(:zip => zip)
|
49
|
+
|
50
|
+
assert_equal 'processing', site.state
|
51
|
+
end
|
52
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitballoon
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Mathias Biilmann Christensen
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-09-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: oauth2
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.9.2
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.2
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: slop
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: highline
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: minitest
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: webmock
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
description: API Client for BitBalloon
|
95
|
+
email:
|
96
|
+
- mathias@bitballoon.com
|
97
|
+
executables:
|
98
|
+
- bitballoon
|
99
|
+
extensions: []
|
100
|
+
extra_rdoc_files: []
|
101
|
+
files:
|
102
|
+
- Gemfile
|
103
|
+
- Gemfile.lock
|
104
|
+
- LICENSE.txt
|
105
|
+
- README.md
|
106
|
+
- Rakefile
|
107
|
+
- bin/bitballoon
|
108
|
+
- bitballoon.gemspec
|
109
|
+
- lib/bitballoon.rb
|
110
|
+
- lib/bitballoon/client.rb
|
111
|
+
- lib/bitballoon/collection_proxy.rb
|
112
|
+
- lib/bitballoon/file.rb
|
113
|
+
- lib/bitballoon/files.rb
|
114
|
+
- lib/bitballoon/form.rb
|
115
|
+
- lib/bitballoon/forms.rb
|
116
|
+
- lib/bitballoon/model.rb
|
117
|
+
- lib/bitballoon/site.rb
|
118
|
+
- lib/bitballoon/sites.rb
|
119
|
+
- lib/bitballoon/submission.rb
|
120
|
+
- lib/bitballoon/submissions.rb
|
121
|
+
- lib/bitballoon/version.rb
|
122
|
+
- test/client_test.rb
|
123
|
+
- test/files/site-dir.zip
|
124
|
+
- test/files/site-dir/index.html
|
125
|
+
- test/sites_test.rb
|
126
|
+
- test/test_helper.rb
|
127
|
+
homepage: https://www.bitballoon.com
|
128
|
+
licenses: []
|
129
|
+
post_install_message:
|
130
|
+
rdoc_options: []
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ! '>='
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ! '>='
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
requirements: []
|
146
|
+
rubyforge_project:
|
147
|
+
rubygems_version: 1.8.23
|
148
|
+
signing_key:
|
149
|
+
specification_version: 3
|
150
|
+
summary: API Client for BitBalloon
|
151
|
+
test_files:
|
152
|
+
- test/client_test.rb
|
153
|
+
- test/files/site-dir.zip
|
154
|
+
- test/files/site-dir/index.html
|
155
|
+
- test/sites_test.rb
|
156
|
+
- test/test_helper.rb
|
157
|
+
has_rdoc:
|