copy-ruby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +1 -0
- data/.travis.yml +5 -0
- data/Gemfile +10 -0
- data/LICENSE +23 -0
- data/README.md +232 -0
- data/Rakefile +8 -0
- data/copy.gemspec +24 -0
- data/lib/copy.rb +85 -0
- data/lib/copy/base.rb +43 -0
- data/lib/copy/client.rb +70 -0
- data/lib/copy/file.rb +134 -0
- data/lib/copy/link.rb +52 -0
- data/lib/copy/operations/activity.rb +27 -0
- data/lib/copy/operations/all.rb +31 -0
- data/lib/copy/operations/base.rb +47 -0
- data/lib/copy/operations/create.rb +20 -0
- data/lib/copy/operations/delete.rb +25 -0
- data/lib/copy/operations/find.rb +21 -0
- data/lib/copy/operations/meta.rb +20 -0
- data/lib/copy/operations/show.rb +20 -0
- data/lib/copy/operations/update.rb +21 -0
- data/lib/copy/request/base.rb +41 -0
- data/lib/copy/request/connection.rb +120 -0
- data/lib/copy/request/helpers.rb +36 -0
- data/lib/copy/request/info.rb +41 -0
- data/lib/copy/request/validator.rb +53 -0
- data/lib/copy/revision.rb +25 -0
- data/lib/copy/session.rb +56 -0
- data/lib/copy/user.rb +24 -0
- data/lib/copy/version.rb +3 -0
- data/spec/copy/base_spec.rb +12 -0
- data/spec/copy/client_spec.rb +69 -0
- data/spec/copy/file_spec.rb +306 -0
- data/spec/copy/link_spec.rb +238 -0
- data/spec/copy/request/base_spec.rb +53 -0
- data/spec/copy/request/connection_spec.rb +73 -0
- data/spec/copy/request/info_spec.rb +27 -0
- data/spec/copy/request/validator_spec.rb +13 -0
- data/spec/copy/revision_spec.rb +42 -0
- data/spec/copy/user_spec.rb +119 -0
- data/spec/copy_spec.rb +52 -0
- data/spec/fixtures/hola.txt +1 -0
- data/spec/spec_helper.rb +12 -0
- metadata +170 -0
@@ -0,0 +1,20 @@
|
|
1
|
+
module Copy
|
2
|
+
module Operations
|
3
|
+
module Show
|
4
|
+
module ClassMethods
|
5
|
+
# Shows a given object
|
6
|
+
#
|
7
|
+
# @param [Integer] id The id of the object that should be shown
|
8
|
+
# @return [Copy::Base] The found object
|
9
|
+
def show(attributes={})
|
10
|
+
response = Copy.request(:get, nil, api_member_url(attributes[:id], :show), {}, options_for_request(attributes))
|
11
|
+
self.new(response)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.included(base)
|
16
|
+
base.extend(ClassMethods)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Copy
|
2
|
+
module Operations
|
3
|
+
module Update
|
4
|
+
module ClassMethods
|
5
|
+
# Updates a object
|
6
|
+
# @param [Integer] id The id of the object that should be updated
|
7
|
+
# @param [Hash] attributes The attributes that should be updated
|
8
|
+
def update(attributes={})
|
9
|
+
id = attributes.delete(:id)
|
10
|
+
session = attributes.delete(:session)
|
11
|
+
response = Copy.request(:put, nil, api_member_url(id, :updated), attributes, options_for_request(session: session))
|
12
|
+
self.new(response)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.included(base)
|
17
|
+
base.extend(ClassMethods)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Copy
|
2
|
+
module Request
|
3
|
+
class Base
|
4
|
+
attr_reader :info
|
5
|
+
attr_accessor :response
|
6
|
+
|
7
|
+
def initialize(info)
|
8
|
+
@info = info
|
9
|
+
end
|
10
|
+
|
11
|
+
def perform
|
12
|
+
raise Copy::AuthenticationError unless valid?
|
13
|
+
connection.set_request_data
|
14
|
+
send_request
|
15
|
+
|
16
|
+
validator.validated_data_for(response)
|
17
|
+
end
|
18
|
+
|
19
|
+
def valid?
|
20
|
+
return false unless info
|
21
|
+
return false unless info.session
|
22
|
+
return false unless info.session.valid?
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def send_request
|
29
|
+
self.response = connection.request
|
30
|
+
end
|
31
|
+
|
32
|
+
def connection
|
33
|
+
@connection ||= Connection.new(info)
|
34
|
+
end
|
35
|
+
|
36
|
+
def validator
|
37
|
+
@validator ||= Validator.new(info)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'net/http/post/multipart'
|
2
|
+
|
3
|
+
module Copy
|
4
|
+
module Request
|
5
|
+
class Connection
|
6
|
+
include Helpers
|
7
|
+
attr_reader :access_token, :request_data
|
8
|
+
|
9
|
+
def initialize(request_info)
|
10
|
+
@info = request_info
|
11
|
+
@session = @info.session if @info
|
12
|
+
@access_token = @info.session.access_token if @session
|
13
|
+
end
|
14
|
+
|
15
|
+
def request
|
16
|
+
return unless access_token
|
17
|
+
if use_body_file?
|
18
|
+
::File.open(body_file_attrs[:local_path]) do |file|
|
19
|
+
req = Net::HTTP::Post::Multipart.new(
|
20
|
+
api_url,
|
21
|
+
'file' => UploadIO.new(
|
22
|
+
file,
|
23
|
+
'application/octet-stream',
|
24
|
+
body_file_attrs[:name]
|
25
|
+
)
|
26
|
+
)
|
27
|
+
access_token.sign! req
|
28
|
+
req['X-Api-Version'] = '1'
|
29
|
+
# Todo finish this to work over https
|
30
|
+
http = Net::HTTP.new("api.copy.com", Net::HTTP.https_default_port)
|
31
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
32
|
+
http.use_ssl = true
|
33
|
+
http.start do |http|
|
34
|
+
http.request(req)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
else
|
38
|
+
access_token.send(*request_data)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def set_request_data
|
43
|
+
@request_data = []
|
44
|
+
@request_data << @info.http_method if @info
|
45
|
+
@request_data << api_url
|
46
|
+
unless use_url_params?
|
47
|
+
@request_data << body_json
|
48
|
+
end
|
49
|
+
@request_data << headers
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
# Body params hash
|
55
|
+
#
|
56
|
+
# @return [Hash]
|
57
|
+
def body_hash
|
58
|
+
return {} unless @info
|
59
|
+
@info.data
|
60
|
+
end
|
61
|
+
|
62
|
+
# Json encoded body
|
63
|
+
#
|
64
|
+
# @return [String]
|
65
|
+
def body_json
|
66
|
+
return '' unless body_hash
|
67
|
+
JSON.generate(body_hash)
|
68
|
+
end
|
69
|
+
|
70
|
+
def body_file_attrs
|
71
|
+
body_hash[:file_attrs] || {}
|
72
|
+
end
|
73
|
+
|
74
|
+
# Body params url encoded
|
75
|
+
#
|
76
|
+
# @return [String]
|
77
|
+
def encoded_www_body
|
78
|
+
return '' unless body_hash
|
79
|
+
URI.encode_www_form(body_hash)
|
80
|
+
end
|
81
|
+
|
82
|
+
def use_body_file?
|
83
|
+
return false if use_url_params?
|
84
|
+
body_hash.has_key?(:file)
|
85
|
+
end
|
86
|
+
|
87
|
+
def use_url_params?
|
88
|
+
return false unless @info
|
89
|
+
case @info.http_method
|
90
|
+
when :post, :put
|
91
|
+
false
|
92
|
+
else
|
93
|
+
true
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def headers
|
98
|
+
{ "X-Api-Version" => API_VERSION }
|
99
|
+
end
|
100
|
+
|
101
|
+
# Returns the api url foir this request or default
|
102
|
+
def api_url
|
103
|
+
url = 'https://' + domain + '.' + API_BASE
|
104
|
+
if @info
|
105
|
+
url += @info.url
|
106
|
+
if use_url_params? && !body_hash.empty?
|
107
|
+
url += '?' + encoded_www_body
|
108
|
+
end
|
109
|
+
end
|
110
|
+
url
|
111
|
+
end
|
112
|
+
|
113
|
+
# Returns the domain for the current request or the default one
|
114
|
+
def domain
|
115
|
+
return @info.subdomain if @info
|
116
|
+
DOMAIN_BASE
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Copy
|
2
|
+
module Request
|
3
|
+
module Helpers
|
4
|
+
def flatten_hash_keys(old_hash, new_hash={}, keys=nil)
|
5
|
+
old_hash.each do |key, value|
|
6
|
+
key = key.to_s
|
7
|
+
if value.is_a?(Hash)
|
8
|
+
all_keys_formatted = keys + "[#{key}]"
|
9
|
+
flatten_hash_keys(value, new_hash, all_keys_formatted)
|
10
|
+
else
|
11
|
+
new_hash[key] = value
|
12
|
+
end
|
13
|
+
end
|
14
|
+
new_hash
|
15
|
+
end
|
16
|
+
|
17
|
+
def normalize_params(params, key=nil)
|
18
|
+
params = flatten_hash_keys(params) if params.is_a?(Hash)
|
19
|
+
result = {}
|
20
|
+
params.each do |key, value|
|
21
|
+
case value
|
22
|
+
when Hash
|
23
|
+
result[key.to_s] = normalize_params(value)
|
24
|
+
when Array
|
25
|
+
value.each_with_index do |item_value, index|
|
26
|
+
result["#{key.to_s}[#{index}]"] = item_value.to_s
|
27
|
+
end
|
28
|
+
else
|
29
|
+
result[key.to_s] = value.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Copy
|
2
|
+
module Request
|
3
|
+
class Info
|
4
|
+
attr_accessor :http_method, :api_url, :data, :subdomain, :session, :base_path
|
5
|
+
|
6
|
+
def initialize(http_method, subdomain, api_url, data, options={})
|
7
|
+
@http_method = http_method
|
8
|
+
@subdomain = subdomain || DOMAIN_BASE
|
9
|
+
@api_url = api_url
|
10
|
+
@data = data
|
11
|
+
@base_path = API_BASE_PATH
|
12
|
+
@session = options[:session]
|
13
|
+
end
|
14
|
+
|
15
|
+
def url
|
16
|
+
url = "/#{base_path}/#{api_url}"
|
17
|
+
if has_id?
|
18
|
+
url += "/#{data[:id]}"
|
19
|
+
data.delete(:id)
|
20
|
+
end
|
21
|
+
|
22
|
+
url
|
23
|
+
end
|
24
|
+
|
25
|
+
def path_with_params(path, params)
|
26
|
+
unless params.empty?
|
27
|
+
encoded_params = URI.encode_www_form(params)
|
28
|
+
[path, encoded_params].join("?")
|
29
|
+
else
|
30
|
+
path
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
|
36
|
+
def has_id?
|
37
|
+
!data[:id].nil?
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Copy
|
2
|
+
module Request
|
3
|
+
class Validator
|
4
|
+
attr_reader :info
|
5
|
+
attr_accessor :response
|
6
|
+
|
7
|
+
def initialize(info)
|
8
|
+
@info = info
|
9
|
+
end
|
10
|
+
|
11
|
+
def validated_data_for(incoming_response)
|
12
|
+
self.response = incoming_response
|
13
|
+
verify_response_code
|
14
|
+
info.data = JSON.parse(response.body) if response.code.to_i != 204
|
15
|
+
info.data ||= {}
|
16
|
+
validate_response_data
|
17
|
+
info.data
|
18
|
+
end
|
19
|
+
|
20
|
+
protected
|
21
|
+
|
22
|
+
def verify_response_code
|
23
|
+
raise AuthenticationError if response.code.to_i == 401
|
24
|
+
raise APIError if response.code.to_i >= 500
|
25
|
+
raise NotFound if response.code.to_i >= 404
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate_response_data
|
29
|
+
body ||= info.data
|
30
|
+
if body.is_a?(Hash)
|
31
|
+
if body['error']
|
32
|
+
handle_api_error(body['error'], body['message'])
|
33
|
+
elsif body['errors']
|
34
|
+
body['errors'].each do |error|
|
35
|
+
handle_api_error(error['code'], error['message'])
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def handle_api_error(code, message)
|
42
|
+
error = case code
|
43
|
+
when 1021, 1024 then ObjectNotFound.new(message)
|
44
|
+
when 1300, 1303 then BadRequest.new(message)
|
45
|
+
else
|
46
|
+
binding.pry
|
47
|
+
APIError.new(message)
|
48
|
+
end
|
49
|
+
fail error
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Copy
|
2
|
+
class Revision < Base
|
3
|
+
|
4
|
+
attr_accessor :id, :revision_id, :modified_time, :size, :latest, :conflict,
|
5
|
+
:type, :creator
|
6
|
+
|
7
|
+
def initialize(attributes = {})
|
8
|
+
super(attributes)
|
9
|
+
parse_creator
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def parse_creator
|
15
|
+
return unless creator
|
16
|
+
@creator = Copy::User.new(creator)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Parses UNIX timestamps and creates Time objects.
|
20
|
+
def parse_timestamps
|
21
|
+
super
|
22
|
+
@modified_time = Time.at(modified_time) if modified_time
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/copy/session.rb
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'oauth'
|
2
|
+
|
3
|
+
module Copy
|
4
|
+
class Session
|
5
|
+
|
6
|
+
attr_accessor :token, :secret, :access_token
|
7
|
+
attr_accessor :consumer_key, :consumer_secret
|
8
|
+
attr_accessor :oauth_verifier, :oauth_token
|
9
|
+
|
10
|
+
OAUTH_URLS = {
|
11
|
+
:site => 'https://api.copy.com',
|
12
|
+
:authorize_url => 'https://www.copy.com/applications/authorize',
|
13
|
+
:request_token_url => 'https://api.copy.com/oauth/request',
|
14
|
+
:access_token_url => 'https://api.copy.com/oauth/access',
|
15
|
+
:http_method => :get
|
16
|
+
}
|
17
|
+
|
18
|
+
def initialize(opts={})
|
19
|
+
@secret = opts[:secret]
|
20
|
+
@token = opts[:token]
|
21
|
+
@consumer_secret = opts[:secret]
|
22
|
+
@consumer_key = opts[:consumer_key] || Copy.configuration[:consumer_key]
|
23
|
+
@consumer_secret = opts[:consumer_secret] || Copy.configuration[:consumer_secret]
|
24
|
+
@oauth_verifier = opts[:oauth_verifier]
|
25
|
+
@oauth_token = opts[:oauth_token]
|
26
|
+
end
|
27
|
+
|
28
|
+
def valid?
|
29
|
+
return false unless token
|
30
|
+
return false unless secret
|
31
|
+
true
|
32
|
+
end
|
33
|
+
|
34
|
+
def consumer
|
35
|
+
@consumer ||= OAuth::Consumer.new(consumer_key, consumer_secret,
|
36
|
+
:site => OAUTH_URLS[:site]
|
37
|
+
# :authorize_url => OAUTH_URLS[:authorize_url],
|
38
|
+
# :request_token_url => OAUTH_URLS[:request_token_url],
|
39
|
+
# :access_token_url => get_access_token_url
|
40
|
+
)
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_access_token_url
|
44
|
+
url = OAUTH_URLS[:request_token_url]
|
45
|
+
url += "?oauth_verifier=#{oauth_verifier}" if oauth_verifier
|
46
|
+
url += "&oauth_token=#{oauth_token}" if oauth_token
|
47
|
+
end
|
48
|
+
|
49
|
+
def access_token
|
50
|
+
@access_token ||= OAuth::AccessToken.new(consumer, token, secret)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
data/lib/copy/user.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
module Copy
|
2
|
+
class User < Base
|
3
|
+
include Copy::Operations::Show
|
4
|
+
include Copy::Operations::Update
|
5
|
+
|
6
|
+
attr_accessor :id, :email, :first_name, :last_name, :developer, :created_time,
|
7
|
+
:emails, :storage, :confirmed, :user_id
|
8
|
+
|
9
|
+
def id
|
10
|
+
@id || @user_id
|
11
|
+
end
|
12
|
+
|
13
|
+
class << self
|
14
|
+
|
15
|
+
# TODO: should be users
|
16
|
+
#
|
17
|
+
def api_resource_name(method=nil)
|
18
|
+
'user'
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|