cloudpt-api 0.0.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 +8 -0
- data/.rspec +1 -0
- data/Gemfile +10 -0
- data/LICENSE +22 -0
- data/README.markdown +322 -0
- data/Rakefile +4 -0
- data/cloudpt-api.gemspec +25 -0
- data/lib/cloudpt-api.rb +22 -0
- data/lib/cloudpt-api/client.rb +72 -0
- data/lib/cloudpt-api/client/files.rb +40 -0
- data/lib/cloudpt-api/client/raw.rb +52 -0
- data/lib/cloudpt-api/connection.rb +34 -0
- data/lib/cloudpt-api/connection/requests.rb +65 -0
- data/lib/cloudpt-api/objects/delta.rb +11 -0
- data/lib/cloudpt-api/objects/dir.rb +20 -0
- data/lib/cloudpt-api/objects/file.rb +44 -0
- data/lib/cloudpt-api/objects/fileops.rb +28 -0
- data/lib/cloudpt-api/objects/object.rb +39 -0
- data/lib/cloudpt-api/tasks.rb +48 -0
- data/lib/cloudpt-api/util/config.rb +27 -0
- data/lib/cloudpt-api/util/error.rb +16 -0
- data/lib/cloudpt-api/util/oauth.rb +29 -0
- data/lib/cloudpt-api/util/util.rb +27 -0
- data/lib/cloudpt-api/version.rb +5 -0
- data/spec/connection.sample.yml +5 -0
- data/spec/fixtures/cloudpt.jpg +0 -0
- data/spec/lib/cloudpt-api/client_spec.rb +208 -0
- data/spec/lib/cloudpt-api/connection_spec.rb +82 -0
- data/spec/lib/cloudpt-api/dir_spec.rb +44 -0
- data/spec/lib/cloudpt-api/file_spec.rb +126 -0
- data/spec/lib/cloudpt-api/oauth_spec.rb +17 -0
- data/spec/lib/cloudpt-api/thumbnail_spec.rb +29 -0
- data/spec/spec_helper.rb +27 -0
- data/spec/support/config.rb +15 -0
- data/spec/support/jpeg.rb +39 -0
- metadata +139 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Client
|
|
5
|
+
|
|
6
|
+
module Files
|
|
7
|
+
|
|
8
|
+
def download(path, options = {})
|
|
9
|
+
root = options.delete(:root) || Cloudpt::API::Config.mode
|
|
10
|
+
path = Cloudpt::API::Util.escape(path)
|
|
11
|
+
url = ["/Storage/CloudPT/Files", root, path].compact.join('/')
|
|
12
|
+
connection.get_raw(:content, url)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def upload(path, data, options = {})
|
|
16
|
+
root = options.delete(:root) || Cloudpt::API::Config.mode
|
|
17
|
+
query = Cloudpt::API::Util.query(options)
|
|
18
|
+
path = Cloudpt::API::Util.escape(path)
|
|
19
|
+
url = ["/Storage/CloudPT/Files", root, path].compact.join('/')
|
|
20
|
+
response = connection.put(:content, "#{url}?#{query}", data, {
|
|
21
|
+
'Content-Type' => "application/octet-stream",
|
|
22
|
+
"Content-Length" => data.length.to_s
|
|
23
|
+
})
|
|
24
|
+
Cloudpt::API::File.init(response, self)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def copy_from_copy_ref(copy_ref, to, options = {})
|
|
28
|
+
raw.copy({
|
|
29
|
+
:from_copy_ref => copy_ref,
|
|
30
|
+
:to_path => to
|
|
31
|
+
}.merge(options))
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Raw
|
|
5
|
+
|
|
6
|
+
attr_accessor :connection
|
|
7
|
+
|
|
8
|
+
def initialize(options = {})
|
|
9
|
+
@connection = options[:connection]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.add_method(method, action, options = {})
|
|
13
|
+
# Add the default root bit, but allow it to be disabled by a config option
|
|
14
|
+
root = options[:root] == false ? '' : "options[:root] ||= Cloudpt::API::Config.mode"
|
|
15
|
+
self.class_eval <<-STR
|
|
16
|
+
def #{options[:as] || action}(options = {})
|
|
17
|
+
#{root}
|
|
18
|
+
request(:#{options[:endpoint] || 'main'}, :#{method}, "#{action}", options)
|
|
19
|
+
end
|
|
20
|
+
STR
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def request(endpoint, method, action, data = {})
|
|
24
|
+
action.sub! ':root', data.delete(:root) if action.match ':root'
|
|
25
|
+
action.sub! ':path', Cloudpt::API::Util.escape(data.delete(:path)) if action.match ':path'
|
|
26
|
+
action = Cloudpt::API::Util.remove_double_slashes(action)
|
|
27
|
+
connection.send(method, endpoint, action, data)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
add_method :get, "/Storage/CloudPT/Account/Info", :as => 'account', :root => false
|
|
31
|
+
|
|
32
|
+
add_method :get, "/Storage/CloudPT/Metadata/:root/:path", :as => 'metadata'
|
|
33
|
+
add_method :post, "/Storage/CloudPT/Delta", :as => 'delta', :root => false
|
|
34
|
+
add_method :get, "/Storage/CloudPT/Revisions/:root/:path", :as => 'revisions'
|
|
35
|
+
add_method :post, "/Storage/CloudPT/Restore/:root/:path", :as => 'restore'
|
|
36
|
+
add_method :get, "/Storage/CloudPT/Search/:root/:path", :as => 'search'
|
|
37
|
+
add_method :post, "/Storage/CloudPT/Shares/:root/:path", :as => 'shares'
|
|
38
|
+
add_method :post, "/Storage/CloudPT/Media/:root/:path", :as => 'media'
|
|
39
|
+
|
|
40
|
+
add_method :get_raw, "/Storage/CloudPT/Thumbnails/:root/:path", :as => 'thumbnails', :endpoint => :content
|
|
41
|
+
|
|
42
|
+
add_method :post, "/Storage/CloudPT/Copy", :as => "copy"
|
|
43
|
+
add_method :get, "/Storage/CloudPT/CopyRef/:root/:path", :as => 'copy_ref'
|
|
44
|
+
add_method :post, "/Storage/CloudPT/CreateFolder", :as => "create_folder"
|
|
45
|
+
add_method :post, "/Storage/CloudPT/Delete", :as => "delete"
|
|
46
|
+
add_method :post, "/Storage/CloudPT/Move", :as => "move"
|
|
47
|
+
add_method :post, "/Storage/CloudPT/List/:root/:path", :as => "list"
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require "cloudpt-api/connection/requests"
|
|
2
|
+
|
|
3
|
+
module Cloudpt
|
|
4
|
+
module API
|
|
5
|
+
|
|
6
|
+
class Connection
|
|
7
|
+
|
|
8
|
+
include Cloudpt::API::Connection::Requests
|
|
9
|
+
|
|
10
|
+
attr_accessor :consumers
|
|
11
|
+
attr_accessor :tokens
|
|
12
|
+
|
|
13
|
+
def initialize(options = {})
|
|
14
|
+
@options = options
|
|
15
|
+
@consumers = {}
|
|
16
|
+
@tokens = {}
|
|
17
|
+
Cloudpt::API::Config.endpoints.each do |endpoint, url|
|
|
18
|
+
@consumers[endpoint] = Cloudpt::API::OAuth.consumer(endpoint)
|
|
19
|
+
@tokens[endpoint] = Cloudpt::API::OAuth.access_token(@consumers[endpoint], options)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def consumer(endpoint = :main)
|
|
24
|
+
@consumers[endpoint]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def token(endpoint = :main)
|
|
28
|
+
@tokens[endpoint]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Connection
|
|
5
|
+
|
|
6
|
+
module Requests
|
|
7
|
+
|
|
8
|
+
def request(options = {})
|
|
9
|
+
response = yield
|
|
10
|
+
raise Cloudpt::API::Error::ConnectionFailed if !response
|
|
11
|
+
status = response.code.to_i
|
|
12
|
+
case status
|
|
13
|
+
when 401
|
|
14
|
+
raise Cloudpt::API::Error::Unauthorized
|
|
15
|
+
when 403
|
|
16
|
+
parsed = MultiJson.decode(response.body)
|
|
17
|
+
raise Cloudpt::API::Error::Forbidden.new(parsed["error"])
|
|
18
|
+
when 404
|
|
19
|
+
raise Cloudpt::API::Error::NotFound
|
|
20
|
+
when 400, 406
|
|
21
|
+
parsed = MultiJson.decode(response.body)
|
|
22
|
+
raise Cloudpt::API::Error.new(parsed["error"])
|
|
23
|
+
when 300..399
|
|
24
|
+
raise Cloudpt::API::Error::Redirect
|
|
25
|
+
when 500..599
|
|
26
|
+
raise Cloudpt::API::Error
|
|
27
|
+
else
|
|
28
|
+
options[:raw] ? response.body : MultiJson.decode(response.body)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def get_raw(endpoint, path, data = {}, headers = {})
|
|
35
|
+
query = Cloudpt::API::Util.query(data)
|
|
36
|
+
request(:raw => true) do
|
|
37
|
+
token(endpoint).get "#{Cloudpt::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def get(endpoint, path, data = {}, headers = {})
|
|
42
|
+
query = Cloudpt::API::Util.query(data)
|
|
43
|
+
request do
|
|
44
|
+
token(endpoint).get "#{Cloudpt::API::Config.prefix}#{path}?#{URI.parse(URI.encode(query))}", headers
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def post(endpoint, path, data = {}, headers = {})
|
|
49
|
+
request do
|
|
50
|
+
token(endpoint).post "#{Cloudpt::API::Config.prefix}#{path}", data, headers
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def put(endpoint, path, data = {}, headers = {})
|
|
55
|
+
request do
|
|
56
|
+
token(endpoint).put "#{Cloudpt::API::Config.prefix}#{path}", data, headers
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Dir < Cloudpt::API::Object
|
|
5
|
+
|
|
6
|
+
include Cloudpt::API::Fileops
|
|
7
|
+
|
|
8
|
+
def ls(path_to_list = '')
|
|
9
|
+
data = client.raw.metadata :path => path + path_to_list
|
|
10
|
+
if data['is_dir']
|
|
11
|
+
Cloudpt::API::Object.convert(data.delete('contents') || [], client)
|
|
12
|
+
else
|
|
13
|
+
[Cloudpt::API::Object.convert(data, client)]
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class File < Cloudpt::API::Object
|
|
5
|
+
|
|
6
|
+
include Cloudpt::API::Fileops
|
|
7
|
+
|
|
8
|
+
def revisions(options = {})
|
|
9
|
+
response = client.raw.revisions({ :path => self.path }.merge(options))
|
|
10
|
+
Cloudpt::API::Object.convert(response, client)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def restore(rev, options = {})
|
|
14
|
+
response = client.raw.restore({ :rev => rev, :path => self.path }.merge(options))
|
|
15
|
+
self.update response
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def share_url(options = {})
|
|
19
|
+
response = client.raw.shares({ :path => self.path }.merge(options))
|
|
20
|
+
Cloudpt::API::Object.init(response, client)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def direct_url(options = {})
|
|
24
|
+
response = client.raw.media({ :path => self.path }.merge(options))
|
|
25
|
+
Cloudpt::API::Object.init(response, client)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def thumbnail(options = {})
|
|
29
|
+
client.raw.thumbnails({ :path => self.path }.merge(options))
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def copy_ref(options = {})
|
|
33
|
+
response = client.raw.copy_ref({ :path => self.path }.merge(options))
|
|
34
|
+
Cloudpt::API::Object.init(response, client)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def download
|
|
38
|
+
client.download(self.path)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
module Fileops
|
|
5
|
+
|
|
6
|
+
def copy(to, options = {})
|
|
7
|
+
response = client.raw.copy({ :from_path => self.path, :to_path => to }.merge(options))
|
|
8
|
+
self.update response
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def move(to, options = {})
|
|
12
|
+
response = client.raw.move({ :from_path => self.path, :to_path => to }.merge(options))
|
|
13
|
+
self.update response
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def destroy(options = {})
|
|
17
|
+
response = client.raw.delete({ :path => self.path }.merge(options))
|
|
18
|
+
self.update response
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def path
|
|
22
|
+
self['path'].sub(/^\//, '')
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Object < Hashie::Mash
|
|
5
|
+
attr_accessor :client
|
|
6
|
+
|
|
7
|
+
def self.init(response, client)
|
|
8
|
+
instance = self.new(response)
|
|
9
|
+
instance.client = client
|
|
10
|
+
instance
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.resolve_class(hash)
|
|
14
|
+
hash['is_dir'] == true ? Cloudpt::API::Dir : Cloudpt::API::File
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.convert(array_or_object, client)
|
|
18
|
+
if array_or_object.is_a?(Array)
|
|
19
|
+
array_or_object.collect do |item|
|
|
20
|
+
resolve_class(item).init(item, client)
|
|
21
|
+
end
|
|
22
|
+
else
|
|
23
|
+
resolve_class(array_or_object).init(array_or_object, client)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Kill off the ability for recursive conversion
|
|
28
|
+
def deep_update(other_hash)
|
|
29
|
+
other_hash.each_pair do |k,v|
|
|
30
|
+
key = convert_key(k)
|
|
31
|
+
regular_writer(key, convert_value(v, true))
|
|
32
|
+
end
|
|
33
|
+
self
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Tasks
|
|
5
|
+
|
|
6
|
+
extend Rake::DSL if defined? Rake::DSL
|
|
7
|
+
|
|
8
|
+
def self.install
|
|
9
|
+
|
|
10
|
+
namespace :cloudpt do
|
|
11
|
+
desc "Authorize wizard for Cloudpt API"
|
|
12
|
+
task :authorize do
|
|
13
|
+
require "cloudpt-api"
|
|
14
|
+
require "cgi"
|
|
15
|
+
print "Enter consumer key: "
|
|
16
|
+
consumer_key = $stdin.gets.chomp
|
|
17
|
+
print "Enter consumer secret: "
|
|
18
|
+
consumer_secret = $stdin.gets.chomp
|
|
19
|
+
|
|
20
|
+
Cloudpt::API::Config.app_key = consumer_key
|
|
21
|
+
Cloudpt::API::Config.app_secret = consumer_secret
|
|
22
|
+
|
|
23
|
+
consumer = Cloudpt::API::OAuth.consumer(:authorize)
|
|
24
|
+
request_token = consumer.get_request_token
|
|
25
|
+
puts "\nGo to this url and click 'Authorize' to get the token:"
|
|
26
|
+
puts request_token.authorize_url
|
|
27
|
+
#query = request_token.authorize_url.split('?').last
|
|
28
|
+
#params = CGI.parse(query)
|
|
29
|
+
#token = params['oauth_token'].first
|
|
30
|
+
print "\nOnce you authorize the app on Cloudpt enter the pin and press enter... "
|
|
31
|
+
token = $stdin.gets.chomp
|
|
32
|
+
|
|
33
|
+
access_token = request_token.get_access_token(:oauth_verifier => token)
|
|
34
|
+
|
|
35
|
+
puts "\nAuthorization complete!:\n\n"
|
|
36
|
+
puts " Cloudpt::API::Config.app_key = '#{consumer.key}'"
|
|
37
|
+
puts " Cloudpt::API::Config.app_secret = '#{consumer.secret}'"
|
|
38
|
+
puts " client = Cloudpt::API::Client.new(:token => '#{access_token.token}', :secret => '#{access_token.secret}')"
|
|
39
|
+
puts "\n"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
module Config
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
attr_accessor :endpoints
|
|
8
|
+
attr_accessor :prefix
|
|
9
|
+
attr_accessor :app_key
|
|
10
|
+
attr_accessor :app_secret
|
|
11
|
+
attr_accessor :mode
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
self.endpoints = {
|
|
15
|
+
:main => "https://api.cloudpt.pt",
|
|
16
|
+
:content => "https://api-content.cloudpt.pt",
|
|
17
|
+
:authorize => "https://cloudpt.pt"
|
|
18
|
+
}
|
|
19
|
+
self.prefix = ""
|
|
20
|
+
self.app_key = nil
|
|
21
|
+
self.app_secret = nil
|
|
22
|
+
self.mode = nil
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
class Error < Exception
|
|
5
|
+
|
|
6
|
+
class ConnectionFailed < Exception; end
|
|
7
|
+
class Config < Exception; end
|
|
8
|
+
class Unauthorized < Exception; end
|
|
9
|
+
class Forbidden < Exception; end
|
|
10
|
+
class NotFound < Exception; end
|
|
11
|
+
class Redirect < Exception; end
|
|
12
|
+
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module Cloudpt
|
|
2
|
+
module API
|
|
3
|
+
|
|
4
|
+
module OAuth
|
|
5
|
+
|
|
6
|
+
class << self
|
|
7
|
+
|
|
8
|
+
def consumer(endpoint)
|
|
9
|
+
if !Cloudpt::API::Config.app_key or !Cloudpt::API::Config.app_secret
|
|
10
|
+
raise Cloudpt::API::Error::Config.new("app_key or app_secret not provided")
|
|
11
|
+
end
|
|
12
|
+
::OAuth::Consumer.new(Cloudpt::API::Config.app_key, Cloudpt::API::Config.app_secret,
|
|
13
|
+
:site => Cloudpt::API::Config.endpoints[endpoint],
|
|
14
|
+
:request_token_path => Cloudpt::API::Config.prefix + "/oauth/request_token",
|
|
15
|
+
:authorize_path => Cloudpt::API::Config.prefix + "/oauth/authorize",
|
|
16
|
+
:access_token_path => Cloudpt::API::Config.prefix + "/oauth/access_token")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def access_token(consumer, options = {})
|
|
20
|
+
::OAuth::AccessToken.new(consumer, options[:token], options[:secret])
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|