uploadcare-ruby 1.0.1.rc1

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.
@@ -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