uploadcare-ruby 1.0.1.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.DS_Store +0 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +42 -0
- data/LICENSE +22 -0
- data/README.md +385 -0
- data/Rakefile +2 -0
- data/lib/uploadcare.rb +43 -0
- data/lib/uploadcare/api.rb +20 -0
- data/lib/uploadcare/api/connections.rb +32 -0
- data/lib/uploadcare/api/file_api.rb +9 -0
- data/lib/uploadcare/api/file_list_api.rb +8 -0
- data/lib/uploadcare/api/group_api.rb +38 -0
- data/lib/uploadcare/api/group_list_api.rb +8 -0
- data/lib/uploadcare/api/parser.rb +42 -0
- data/lib/uploadcare/api/project_api.rb +9 -0
- data/lib/uploadcare/api/raw_api.rb +73 -0
- data/lib/uploadcare/api/uploading_api.rb +122 -0
- data/lib/uploadcare/resources/file.rb +136 -0
- data/lib/uploadcare/resources/file_list.rb +41 -0
- data/lib/uploadcare/resources/group.rb +116 -0
- data/lib/uploadcare/resources/group_list.rb +31 -0
- data/lib/uploadcare/resources/project.rb +21 -0
- data/lib/uploadcare/version.rb +3 -0
- data/spec/file_list_spec.rb +65 -0
- data/spec/file_spec.rb +105 -0
- data/spec/group_list_spec.rb +31 -0
- data/spec/group_spec.rb +90 -0
- data/spec/operations_spec.rb +60 -0
- data/spec/parser_spec.rb +87 -0
- data/spec/project_spec.rb +21 -0
- data/spec/raw_api_spec.rb +25 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/uploading_multiple_spec.rb +45 -0
- data/spec/uploading_spec.rb +40 -0
- data/spec/view.png +0 -0
- data/spec/view2.jpg +0 -0
- data/uploadcare-ruby.gemspec +35 -0
- metadata +184 -0
data/Rakefile
ADDED
data/lib/uploadcare.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
require 'ostruct'
|
4
|
+
|
5
|
+
require 'uploadcare/api'
|
6
|
+
require 'uploadcare/version'
|
7
|
+
|
8
|
+
module Uploadcare
|
9
|
+
DEFAULT_SETTINGS = {
|
10
|
+
public_key: 'demopublickey',
|
11
|
+
private_key: 'demoprivatekey',
|
12
|
+
upload_url_base: 'https://upload.uploadcare.com',
|
13
|
+
api_url_base: 'https://api.uploadcare.com',
|
14
|
+
static_url_base: 'http://www.ucarecdn.com',
|
15
|
+
api_version: '0.3',
|
16
|
+
cache_files: true,
|
17
|
+
}
|
18
|
+
|
19
|
+
USER_AGENT = "uploadcare-ruby/#{Uploadcare::VERSION}"
|
20
|
+
|
21
|
+
|
22
|
+
def self.default_settings
|
23
|
+
DEFAULT_SETTINGS
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.user_agent
|
27
|
+
USER_AGENT
|
28
|
+
end
|
29
|
+
|
30
|
+
UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
31
|
+
|
32
|
+
GROUP_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}~(?<count>\d+)$/
|
33
|
+
|
34
|
+
CDN_URL_FILE_REGEX = /
|
35
|
+
(?<uuid>[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12})
|
36
|
+
(?:\/-\/(?<operations>.*?))?\/?$
|
37
|
+
/ix
|
38
|
+
|
39
|
+
CDN_URL_GROUP_REGEX = /
|
40
|
+
(?<uuid>[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}~(?<count>\d+))
|
41
|
+
(?:\/-\/(?<operations>.*?))?\/?$
|
42
|
+
/ix
|
43
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
Dir[File.dirname(__FILE__) + '/api/*.rb'].each {|file| require file }
|
5
|
+
Dir[File.dirname(__FILE__) + '/resources/*.rb'].each {|file| require file }
|
6
|
+
|
7
|
+
|
8
|
+
module Uploadcare
|
9
|
+
class Api
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
include Uploadcare::RawApi
|
13
|
+
include Uploadcare::UploadingApi
|
14
|
+
include Uploadcare::FileApi
|
15
|
+
include Uploadcare::ProjectApi
|
16
|
+
include Uploadcare::FileListApi
|
17
|
+
include Uploadcare::GroupApi
|
18
|
+
include Uploadcare::GroupListApi
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
|
4
|
+
module Uploadcare
|
5
|
+
class Connections
|
6
|
+
def self.api_connection options
|
7
|
+
connection = Faraday.new url: options[:api_url_base] do |frd|
|
8
|
+
frd.request :url_encoded
|
9
|
+
frd.use FaradayMiddleware::FollowRedirects, limit: 3
|
10
|
+
frd.adapter :net_http # actually, default adapter, just to be clear
|
11
|
+
frd.headers['Authorization'] = "Uploadcare.Simple #{options[:public_key]}:#{options[:private_key]}"
|
12
|
+
frd.headers['Accept'] = "application/vnd.uploadcare-v#{options[:api_version]}+json"
|
13
|
+
frd.headers['User-Agent'] = Uploadcare::user_agent
|
14
|
+
end
|
15
|
+
|
16
|
+
connection
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.upload_connection options
|
20
|
+
ca_path = '/etc/ssl/certs' if File.exists?('/etc/ssl/certs')
|
21
|
+
|
22
|
+
connection = Faraday.new ssl: { ca_path: ca_path }, url: options[:upload_url_base] do |frd|
|
23
|
+
frd.request :multipart
|
24
|
+
frd.request :url_encoded
|
25
|
+
frd.adapter Faraday.default_adapter
|
26
|
+
frd.headers['User-Agent'] = Uploadcare::user_agent
|
27
|
+
end
|
28
|
+
|
29
|
+
connection
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Uploadcare
|
2
|
+
module GroupApi
|
3
|
+
|
4
|
+
def group uuid_or_cdn_url
|
5
|
+
group = Uploadcare::Api::Group.new self, uuid_or_cdn_url
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
def create_group ary
|
10
|
+
unless ary.kind_of?(Array)
|
11
|
+
raise ArgumentError.new "You should send and array of files or valid UUIDs"
|
12
|
+
else
|
13
|
+
if ary.select {|f| !!f.kind_of?(Uploadcare::Api::File) }.any?
|
14
|
+
files = Hash.new
|
15
|
+
ary.each_with_index do |file, i|
|
16
|
+
files["files[#{i}]"] = file.uuid
|
17
|
+
end
|
18
|
+
elsif ary.select {|f| !!f.kind_of?(String) }.any?
|
19
|
+
files = Hash.new
|
20
|
+
ary.each_with_index do |uuid, i|
|
21
|
+
files["files[#{i}]"] = uuid
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise ArgumentError.new "You should send and array of files or valid UUIDs"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
data = {
|
30
|
+
pub_key: @options[:public_key],
|
31
|
+
}
|
32
|
+
|
33
|
+
data.merge! files
|
34
|
+
post = parse(upload_request :post, "/group/", data)
|
35
|
+
group = Uploadcare::Api::Group.new self, post["id"], post
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Uploadcare
|
4
|
+
module Parser
|
5
|
+
|
6
|
+
META_URL = /
|
7
|
+
(?<uuid>[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12} # base uuid
|
8
|
+
~?(?<count>\d+)?) # optional count
|
9
|
+
(?:\/-\/(?<operations>.*?))?\/?$ # optional operations
|
10
|
+
/ix
|
11
|
+
|
12
|
+
def self.parse string
|
13
|
+
matched = META_URL.match(string)
|
14
|
+
|
15
|
+
# just a simple hash - easy to pass next
|
16
|
+
captured = Hash[ matched.names.zip( matched.captures ) ]
|
17
|
+
|
18
|
+
# raise an error if no uuid was given in the sting
|
19
|
+
raise "Invalid UUID or url was given" if captured["uuid"].nil?
|
20
|
+
|
21
|
+
# operations sring to array of operations
|
22
|
+
if captured["operations"]
|
23
|
+
captured["operations"] = captured["operations"].split("/-/")
|
24
|
+
else
|
25
|
+
captured["operations"] = []
|
26
|
+
end
|
27
|
+
|
28
|
+
# if count was given - it is a group
|
29
|
+
if captured["count"]
|
30
|
+
obj = Group.new captured
|
31
|
+
else
|
32
|
+
obj = File.new captured
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class File < OpenStruct
|
37
|
+
end
|
38
|
+
|
39
|
+
class Group < OpenStruct
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
require 'uploadcare/api/connections'
|
4
|
+
|
5
|
+
module Uploadcare
|
6
|
+
module RawApi
|
7
|
+
|
8
|
+
def initialize options={}
|
9
|
+
@options = Uploadcare::default_settings.merge(options)
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
# basic request method
|
14
|
+
def request method = :get, path = "/files/", params = {}
|
15
|
+
response = send_request(method, path, params)
|
16
|
+
parse(response)
|
17
|
+
end
|
18
|
+
alias_method :api_request, :request
|
19
|
+
|
20
|
+
|
21
|
+
# request with GET verb
|
22
|
+
def get path= "/files/", params={}
|
23
|
+
request :get, path, params
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
# request with POST verb
|
28
|
+
def post path= "/files/", params={}
|
29
|
+
request :post, path, params
|
30
|
+
end
|
31
|
+
|
32
|
+
# request with PUT verb
|
33
|
+
def put path= "/files/", params={}
|
34
|
+
request :put, path, params
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
# request with DELETE verb
|
39
|
+
def delete path= "/files/", params={}
|
40
|
+
request :delete, path, params
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
protected
|
45
|
+
def send_request method, path, params={}
|
46
|
+
connection = Uploadcare::Connections.api_connection(@options)
|
47
|
+
response = connection.send method, path, params
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def parse response
|
52
|
+
begin
|
53
|
+
object = JSON.parse(response.body)
|
54
|
+
rescue JSON::ParserError
|
55
|
+
object = false
|
56
|
+
end
|
57
|
+
|
58
|
+
# and returning the object (file actually) or raise new error
|
59
|
+
if response.status < 300
|
60
|
+
object
|
61
|
+
else
|
62
|
+
message = "HTTP code #{response.status}"
|
63
|
+
if object # add active_support god damn it
|
64
|
+
message += ": #{object["detail"]}"
|
65
|
+
else
|
66
|
+
message += ": unknown error occured."
|
67
|
+
end
|
68
|
+
|
69
|
+
raise ArgumentError.new(message)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
require "uri"
|
2
|
+
require 'mime/types'
|
3
|
+
|
4
|
+
module Uploadcare
|
5
|
+
module UploadingApi
|
6
|
+
# intelegent guess for file or url uploading
|
7
|
+
def upload object
|
8
|
+
# if object is file - uploading it as file
|
9
|
+
if object.kind_of?(File)
|
10
|
+
upload_file(object)
|
11
|
+
|
12
|
+
# if a string - try to upload as url
|
13
|
+
elsif object.kind_of?(String)
|
14
|
+
upload_url(object)
|
15
|
+
|
16
|
+
# array of files
|
17
|
+
elsif object.kind_of?(Array)
|
18
|
+
upload_files(object)
|
19
|
+
|
20
|
+
else
|
21
|
+
raise ArgumentError.new "you should give File object, array of files or valid url string"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def upload_files files
|
27
|
+
if files.select {|f| !f.kind_of?(File)}.any?
|
28
|
+
raise ArgumentError.new "one or more of given files is not actually files"
|
29
|
+
else
|
30
|
+
data = {
|
31
|
+
UPLOADCARE_PUB_KEY: @options[:public_key],
|
32
|
+
}
|
33
|
+
|
34
|
+
files.each_with_index do |f, i|
|
35
|
+
data["file[#{i}]"] = Faraday::UploadIO.new(f.path, extract_mime_type(f))
|
36
|
+
end
|
37
|
+
|
38
|
+
response = upload_request :post, '/base/', data
|
39
|
+
uuids = upload_parse(response)
|
40
|
+
|
41
|
+
files = uuids.values.map! {|f| Uploadcare::Api::File.new self, f }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
# upload file to servise
|
47
|
+
def upload_file file
|
48
|
+
if file.kind_of?(File)
|
49
|
+
mime_type = extract_mime_type(file)
|
50
|
+
|
51
|
+
response = upload_request :post, '/base/', {
|
52
|
+
UPLOADCARE_PUB_KEY: @options[:public_key],
|
53
|
+
file: Faraday::UploadIO.new(file.path, mime_type)
|
54
|
+
}
|
55
|
+
uuid = upload_parse(response)["file"]
|
56
|
+
Uploadcare::Api::File.new self, uuid
|
57
|
+
else
|
58
|
+
raise ArgumentError.new 'expecting File object'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# create file is the same as uplaod file
|
63
|
+
alias_method :create_file, :upload_file
|
64
|
+
|
65
|
+
|
66
|
+
#upload from url
|
67
|
+
def upload_url url
|
68
|
+
uri = URI.parse(url)
|
69
|
+
|
70
|
+
if uri.kind_of?(URI::HTTP) # works both for HTTP and HTTPS as HTTPS inherits from HTTP
|
71
|
+
token = get_token(url)
|
72
|
+
|
73
|
+
while (response = get_status_response(token))['status'] == 'unknown'
|
74
|
+
sleep 0.5
|
75
|
+
end
|
76
|
+
|
77
|
+
raise ArgumentError.new(response['error']) if response['status'] == 'error'
|
78
|
+
uuid = response['file_id']
|
79
|
+
Uploadcare::Api::File.new self, uuid
|
80
|
+
else
|
81
|
+
raise ArgumentError.new 'invalid url was given'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
alias_method :upload_from_url, :upload_url
|
85
|
+
|
86
|
+
|
87
|
+
|
88
|
+
|
89
|
+
protected
|
90
|
+
def upload_request method, path, params = {}
|
91
|
+
connection = Uploadcare::Connections.upload_connection(@options)
|
92
|
+
response = connection.send method, path, params
|
93
|
+
end
|
94
|
+
|
95
|
+
|
96
|
+
def upload_parse response
|
97
|
+
raise ArgumentError.new(response.body) if response.status > 200
|
98
|
+
begin
|
99
|
+
JSON.parse(response.body)
|
100
|
+
rescue JSON::ParserError
|
101
|
+
response.body
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
|
106
|
+
private
|
107
|
+
def get_status_response token
|
108
|
+
upload_parse(upload_request(:post, '/from_url/status/', {token: token}))
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
def get_token url
|
113
|
+
response = upload_request :post, '/from_url/', { source_url: url, pub_key: @options[:public_key] }
|
114
|
+
token = upload_parse(response)["token"]
|
115
|
+
end
|
116
|
+
|
117
|
+
def extract_mime_type file
|
118
|
+
types = MIME::Types.of(file.path)
|
119
|
+
types[0].content_type
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module Uploadcare
|
4
|
+
class Api
|
5
|
+
class File < OpenStruct
|
6
|
+
def initialize api, uuid_or_cdn_url, data=nil
|
7
|
+
result = Uploadcare::Parser.parse(uuid_or_cdn_url)
|
8
|
+
|
9
|
+
unless result.is_a?(Uploadcare::Parser::File)
|
10
|
+
msg = "invalid CDN URL or UUID was given for file: #{uuid_or_cdn_url}."
|
11
|
+
if result.is_a?(Uploadcare::Parser::Group)
|
12
|
+
msg = msg + "\n Group UUID was given. Try call @api.group if it is what you intended."
|
13
|
+
end
|
14
|
+
raise msg
|
15
|
+
end
|
16
|
+
|
17
|
+
file = {uuid: result["uuid"], operations: result["operations"]}
|
18
|
+
|
19
|
+
@api = api
|
20
|
+
|
21
|
+
super file
|
22
|
+
|
23
|
+
set_data(data) if data
|
24
|
+
end
|
25
|
+
|
26
|
+
def cdn_url add_operations=false
|
27
|
+
if add_operations
|
28
|
+
cdn_url_with_operations
|
29
|
+
else
|
30
|
+
cdn_url_without_operations
|
31
|
+
end
|
32
|
+
end
|
33
|
+
alias_method :public_url, :cdn_url
|
34
|
+
|
35
|
+
|
36
|
+
def cdn_url_without_operations
|
37
|
+
@api.options[:static_url_base] + "/#{@table[:uuid]}/"
|
38
|
+
end
|
39
|
+
alias_method :public_url_without_operations, :cdn_url_without_operations
|
40
|
+
|
41
|
+
|
42
|
+
def cdn_url_with_operations
|
43
|
+
url = cdn_url_without_operations
|
44
|
+
unless operations.empty?
|
45
|
+
ops = operations.join("/-/")
|
46
|
+
url = url + "-/#{ops}/"
|
47
|
+
end
|
48
|
+
url
|
49
|
+
end
|
50
|
+
alias_method :public_url_with_operations, :cdn_url_with_operations
|
51
|
+
|
52
|
+
|
53
|
+
def load_data
|
54
|
+
load_data! unless is_loaded?
|
55
|
+
self
|
56
|
+
end
|
57
|
+
alias_method :load, :load_data
|
58
|
+
|
59
|
+
def load_data!
|
60
|
+
data = @api.get "/files/#{uuid}/"
|
61
|
+
set_data(data)
|
62
|
+
|
63
|
+
self
|
64
|
+
end
|
65
|
+
alias_method :load!, :load_data!
|
66
|
+
|
67
|
+
def is_loaded?
|
68
|
+
!send(:datetime_uploaded).nil?
|
69
|
+
end
|
70
|
+
alias_method :loaded?, :is_loaded?
|
71
|
+
|
72
|
+
|
73
|
+
def store
|
74
|
+
data = @api.put "/files/#{uuid}/storage/"
|
75
|
+
set_data data
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
# nil is returning if there is no way to say for sure
|
80
|
+
def is_stored?
|
81
|
+
return nil unless is_loaded?
|
82
|
+
!send(:datetime_stored).nil?
|
83
|
+
end
|
84
|
+
alias_method :stored?, :is_stored?
|
85
|
+
|
86
|
+
|
87
|
+
def delete
|
88
|
+
data = @api.delete "/files/#{uuid}/storage/"
|
89
|
+
set_data data
|
90
|
+
self
|
91
|
+
end
|
92
|
+
|
93
|
+
# nil is returning if there is no way to say for sure
|
94
|
+
def is_deleted?
|
95
|
+
return nil unless is_loaded?
|
96
|
+
!send(:datetime_removed).nil?
|
97
|
+
end
|
98
|
+
alias_method :deleted?, :is_deleted?
|
99
|
+
alias_method :removed?, :is_deleted?
|
100
|
+
alias_method :is_removed?, :is_deleted?
|
101
|
+
|
102
|
+
|
103
|
+
# Datetime methods
|
104
|
+
# practicly try and parse the string to date objects
|
105
|
+
["original", "uploaded", "stored", "removed"].each do |dt|
|
106
|
+
define_method "datetime_#{dt}" do
|
107
|
+
date = @table["datetime_#{dt}".to_sym]
|
108
|
+
if date.is_a?(String)
|
109
|
+
begin
|
110
|
+
parsed = DateTime.parse(date)
|
111
|
+
self.send("datetime_#{dt}=", parsed)
|
112
|
+
parsed
|
113
|
+
rescue Exception => e
|
114
|
+
date
|
115
|
+
end
|
116
|
+
else
|
117
|
+
date
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
alias_method :datetime_deleted, :datetime_removed
|
122
|
+
|
123
|
+
|
124
|
+
private
|
125
|
+
def set_data data
|
126
|
+
if data.respond_to? :each
|
127
|
+
data.each do |key, value|
|
128
|
+
self.send "#{key}=", value
|
129
|
+
end
|
130
|
+
else
|
131
|
+
self.data = data
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|