uploadcare-ruby 1.0.1.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -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,9 @@
1
+ require "uri"
2
+
3
+ module Uploadcare
4
+ module FileApi
5
+ def file uuid_or_cdn_url
6
+ file = Uploadcare::Api::File.new self, uuid_or_cdn_url
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,8 @@
1
+ module Uploadcare
2
+ module FileListApi
3
+ def file_list page=1
4
+ data = get '/files/', {page: page}
5
+ list = Uploadcare::Api::FileList.new self, data
6
+ end
7
+ end
8
+ 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,8 @@
1
+ module Uploadcare
2
+ module GroupListApi
3
+ def group_list from=nil, limit=nil
4
+ data = get '/groups/', {from: from, limit: limit}
5
+ list = Uploadcare::Api::GroupList.new self, data
6
+ end
7
+ end
8
+ 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,9 @@
1
+ require "uri"
2
+
3
+ module Uploadcare
4
+ module ProjectApi
5
+ def project
6
+ @project ||= Uploadcare::Api::Project.new self
7
+ end
8
+ end
9
+ 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