imagekitio 1.0.3
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.
- checksums.yaml +7 -0
- data/README.md +517 -0
- data/Rakefile +27 -0
- data/lib/carrierwave/storage/ik_file.rb +50 -0
- data/lib/carrierwave/storage/imagekit_store.rb +68 -0
- data/lib/carrierwave/support/uri_filename.rb +10 -0
- data/lib/imagekit/constants/defaults.rb +20 -0
- data/lib/imagekit/constants/errors.rb +71 -0
- data/lib/imagekit/constants/file.rb +5 -0
- data/lib/imagekit/constants/supported_transformation.rb +44 -0
- data/lib/imagekit/constants/url.rb +9 -0
- data/lib/imagekit/file.rb +133 -0
- data/lib/imagekit/imagekit.rb +108 -0
- data/lib/imagekit/resource.rb +55 -0
- data/lib/imagekit/sdk/version.rb +5 -0
- data/lib/imagekit/url.rb +228 -0
- data/lib/imagekit/utils/calculation.rb +36 -0
- data/lib/imagekit/utils/formatter.rb +29 -0
- data/lib/imagekitio.rb +72 -0
- data/lib/imagekitio/railtie.rb +4 -0
- data/lib/tasks/imagekitio/imagekitio_tasks.rake +4 -0
- metadata +124 -0
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'Imagekit::Sdk'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.md')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
require 'bundler/gem_tasks'
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
|
21
|
+
Rake::TestTask.new(:test) do |t|
|
22
|
+
t.libs << 'test'
|
23
|
+
t.pattern = 'test/**/*_test.rb'
|
24
|
+
t.verbose = false
|
25
|
+
end
|
26
|
+
|
27
|
+
task default: :test
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CarrierWave
|
2
|
+
module Storage
|
3
|
+
class IKFile
|
4
|
+
# Initialize as required.
|
5
|
+
|
6
|
+
def initialize(identifier)
|
7
|
+
@identifier=JSON.parse(identifier)
|
8
|
+
ik_config=Rails.application.config.imagekit
|
9
|
+
@imagekit=ImageKit::ImageKitClient.new(ik_config[:private_key],ik_config[:public_key],ik_config[:url_endpoint])
|
10
|
+
end
|
11
|
+
|
12
|
+
# Duck-type methods for CarrierWave::SanitizedFile.
|
13
|
+
def content_type
|
14
|
+
"image/jpg"
|
15
|
+
end
|
16
|
+
def public_url
|
17
|
+
@identifier['url']
|
18
|
+
end
|
19
|
+
def url(options = {})
|
20
|
+
@identifier['url']
|
21
|
+
end
|
22
|
+
|
23
|
+
def fileId
|
24
|
+
@identifier['fileId']
|
25
|
+
end
|
26
|
+
def filename(options = {})
|
27
|
+
@identifier['name']
|
28
|
+
end
|
29
|
+
def read
|
30
|
+
end
|
31
|
+
def size
|
32
|
+
end
|
33
|
+
def delete
|
34
|
+
# file_id=@identifier['fileId']
|
35
|
+
begin
|
36
|
+
@imagekit.delete_file(fileId)
|
37
|
+
rescue
|
38
|
+
fileId
|
39
|
+
end
|
40
|
+
# binding.pry
|
41
|
+
# return nil
|
42
|
+
end
|
43
|
+
def exists?
|
44
|
+
end
|
45
|
+
# Others... ?
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'net/http'
|
3
|
+
require 'base64'
|
4
|
+
module CarrierWave
|
5
|
+
module Storage
|
6
|
+
class ImageKitStore < Abstract
|
7
|
+
|
8
|
+
def initialize(*)
|
9
|
+
super
|
10
|
+
@cache_called = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def store!(file)
|
14
|
+
file.delete
|
15
|
+
end
|
16
|
+
|
17
|
+
def retrieve!(identifier)
|
18
|
+
|
19
|
+
IKFile.new(identifier)
|
20
|
+
end
|
21
|
+
|
22
|
+
def cache!(new_file)
|
23
|
+
new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
|
24
|
+
rescue Errno::EMLINK, Errno::ENOSPC => e
|
25
|
+
raise(e) if @cache_called
|
26
|
+
@cache_called = true
|
27
|
+
|
28
|
+
# NOTE: Remove cached files older than 10 minutes
|
29
|
+
clean_cache!(600)
|
30
|
+
|
31
|
+
cache!(new_file)
|
32
|
+
end
|
33
|
+
|
34
|
+
def retrieve_from_cache!(identifier)
|
35
|
+
CarrierWave::SanitizedFile.new(::File.expand_path(uploader.cache_path(identifier), uploader.root))
|
36
|
+
resp=@client.get(identifier)
|
37
|
+
# binding.pry
|
38
|
+
IKFile.new(resp)
|
39
|
+
end
|
40
|
+
|
41
|
+
def delete_dir!(path)
|
42
|
+
if path
|
43
|
+
begin
|
44
|
+
Dir.rmdir(::File.expand_path(path, uploader.root))
|
45
|
+
rescue Errno::ENOENT
|
46
|
+
# Ignore: path does not exist
|
47
|
+
rescue Errno::ENOTDIR
|
48
|
+
# Ignore: path is not a dir
|
49
|
+
rescue Errno::ENOTEMPTY, Errno::EEXIST
|
50
|
+
# Ignore: dir is not empty
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def clean_cache!(seconds)
|
56
|
+
Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), CarrierWave.root)).each do |dir|
|
57
|
+
# generate_cache_id returns key formated TIMEINT-PID(-COUNTER)-RND
|
58
|
+
time = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first.map(&:to_i)
|
59
|
+
time = Time.at(*time)
|
60
|
+
if time < (Time.now.utc - seconds)
|
61
|
+
FileUtils.rm_rf(dir)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Enum for defaults
|
4
|
+
|
5
|
+
class Default
|
6
|
+
TRANSFORMATION_POSITION = "path"
|
7
|
+
QUERY_TRANSFORMATION_POSITION = "query"
|
8
|
+
VALID_TRANSFORMATION_POSITION = [TRANSFORMATION_POSITION,
|
9
|
+
QUERY_TRANSFORMATION_POSITION,].freeze
|
10
|
+
DEFAULT_TIMESTAMP = "9999999999"
|
11
|
+
TRANSFORMATION_PARAMETER = "tr"
|
12
|
+
CHAIN_TRANSFORM_DELIMITER = ":"
|
13
|
+
TRANSFORM_DELIMITER = ","
|
14
|
+
TRANSFORM_KEY_VALUE_DELIMITER = "-"
|
15
|
+
|
16
|
+
SIGNATURE_PARAMETER = "ik-s"
|
17
|
+
TIMESTAMP_PARAMETER = "ik-t"
|
18
|
+
TIMESTAMP = "9999999999"
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
MANDATORY_INIT_MISSING = {
|
2
|
+
'message': "Missing public_key or private_key or url_endpoint during ImageKit initialization",
|
3
|
+
help: "",
|
4
|
+
}
|
5
|
+
INVALID_TRANSFORMATION_POS = {'message': "Invalid transformationPosition parameter",
|
6
|
+
help: "",}
|
7
|
+
INVALID_URL_GENERATION_PARAM = {'message': "Invalid url parameter", help: ""}
|
8
|
+
INVALID_TRANSFORMATION_OPTIONS = {
|
9
|
+
'message': "Invalid transformation parameter options",
|
10
|
+
help: "",
|
11
|
+
}
|
12
|
+
CACHE_PURGE_URL_MISSING = {'message': "Missing URL parameter for this request",
|
13
|
+
help: "",}
|
14
|
+
CACHE_PURGE_STATUS_ID_MISSING = {'message': "Missing Request ID parameter for this request",
|
15
|
+
help: "",}
|
16
|
+
FILE_ID_MISSING = {'message': "Missing File ID parameter for this request",
|
17
|
+
help: "",}
|
18
|
+
UPDATE_DATA_MISSING = {'message': "Missing file update data for this request",
|
19
|
+
help: "",}
|
20
|
+
|
21
|
+
UPDATE_DATA_TAGS_INVALID = {'message': "Invalid tags parameter for this request",
|
22
|
+
help: "tags should be passed as null or an array like ['tag1', 'tag2']",}.freeze
|
23
|
+
|
24
|
+
UPDATE_DATA_COORDS_INVALID =
|
25
|
+
{'message': "Invalid custom_coordinates parameter for this request",
|
26
|
+
help: "custom_coordinates should be passed as null or a string like 'x,y,width,height'",}
|
27
|
+
|
28
|
+
LIST_FILES_INPUT_MISSING = {
|
29
|
+
'message': "Missing options for list files",
|
30
|
+
help: "If you do not want to pass any parameter for listing, pass an empty object",
|
31
|
+
}
|
32
|
+
MISSING_FILE_URL = {'message': "Missing file_url for purge_cache", help: ""}
|
33
|
+
MISSING_UPLOAD_DATA = {'message': "Missing data for upload", help: ""}
|
34
|
+
MISSING_UPLOAD_FILE_PARAMETER = {
|
35
|
+
'message': "Missing file parameter for upload",
|
36
|
+
help: "",
|
37
|
+
}
|
38
|
+
MISSING_UPLOAD_FILENAME_PARAM = {
|
39
|
+
'message': "Missing fileName parameter for upload",
|
40
|
+
help: "",
|
41
|
+
}
|
42
|
+
|
43
|
+
INVALID_PHASH_VALUE =
|
44
|
+
{
|
45
|
+
'message': "Invalid pHash value",
|
46
|
+
help: "Both pHash strings must be valid hexadecimal numbers",
|
47
|
+
}
|
48
|
+
|
49
|
+
MISSING_PHASH_VALUE = {
|
50
|
+
'message': "Missing pHash value",
|
51
|
+
help: "Please pass two pHash values",
|
52
|
+
}
|
53
|
+
UNEQUAL_STRING_LENGTH = {
|
54
|
+
'': "Unequal pHash string length",
|
55
|
+
help: "For distance calculation, the two pHash strings must have equal length",
|
56
|
+
}
|
57
|
+
|
58
|
+
MISSING_UPLOAD_FILE_PARAMETER = {'message': "Missing file parameter for upload",
|
59
|
+
'help': "",}
|
60
|
+
MISSING_UPLOAD_FILENAME_PARAM = {
|
61
|
+
'message': "Missing fileName parameter for upload",
|
62
|
+
'help': "",
|
63
|
+
}
|
64
|
+
|
65
|
+
INVALID_PHASH_VALUE = {'message': "Invalid pHash value",
|
66
|
+
'help': "Both pHash strings must be valid hexadecimal numbers",}
|
67
|
+
|
68
|
+
MISSING_PHASH_VALUE = {'message': "Missing pHash value",
|
69
|
+
'help': "Please pass two pHash values",}
|
70
|
+
UNEQUAL_STRING_LENGTH = {'message': "Unequal pHash string length",
|
71
|
+
'help': "For distance calculation, the two pHash strings must have equal length",}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
SUPPORTED_TRANS = {
|
2
|
+
'height': "h",
|
3
|
+
'width': "w",
|
4
|
+
'aspect_ratio': "ar",
|
5
|
+
'quality': "q",
|
6
|
+
'crop': "c",
|
7
|
+
'crop_mode': "cm",
|
8
|
+
'x': "x",
|
9
|
+
'y': "y",
|
10
|
+
'focus': "fo",
|
11
|
+
'format': "f",
|
12
|
+
'radius': "r",
|
13
|
+
'background': "bg",
|
14
|
+
'border': "bo",
|
15
|
+
'rotation': "rt",
|
16
|
+
'blur': "bl",
|
17
|
+
'named': "n",
|
18
|
+
'overlay_image': "oi",
|
19
|
+
'overlay_x': "ox",
|
20
|
+
'overlay_y': "oy",
|
21
|
+
'overlay_focus': "ofo",
|
22
|
+
'overlay_height': "oh",
|
23
|
+
'overlay_width': "ow",
|
24
|
+
'overlay_text': "ot",
|
25
|
+
'overlay_text_font_size': "ots",
|
26
|
+
'overlay_text_font_family': "otf",
|
27
|
+
'overlay_text_color': "otc",
|
28
|
+
'overlay_alpha': "oa",
|
29
|
+
'overlay_text_typography': "ott",
|
30
|
+
'overlay_background': "obg",
|
31
|
+
'overlay_image_trim': "oit",
|
32
|
+
'progressive': "pr",
|
33
|
+
'lossless': "lo",
|
34
|
+
'trim': "t",
|
35
|
+
'metadata': "md",
|
36
|
+
'color_profile': "cp",
|
37
|
+
'default_image': "di",
|
38
|
+
'dpr': "dpr",
|
39
|
+
'effect_sharpen': "e-sharpen",
|
40
|
+
'effect_usm': "e-usm",
|
41
|
+
'effect_contrast': "e-contrast",
|
42
|
+
'effect_gray': "e-grayscale",
|
43
|
+
'original': "orig",
|
44
|
+
}
|
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "./constants/errors"
|
4
|
+
require_relative "./constants/file"
|
5
|
+
require_relative "./constants/url"
|
6
|
+
|
7
|
+
require_relative "./utils/formatter"
|
8
|
+
|
9
|
+
class ImageKitFile
|
10
|
+
# This File class holds file related operations like
|
11
|
+
# upload, list etc
|
12
|
+
def initialize(req_obj)
|
13
|
+
@req_obj = req_obj
|
14
|
+
end
|
15
|
+
|
16
|
+
def upload(file, file_name, options)
|
17
|
+
# uploads files with required arguments
|
18
|
+
# supports bot url and binary
|
19
|
+
raise ArgumentError, MISSING_UPLOAD_FILE_PARAMETER unless file
|
20
|
+
raise ArgumentError, MISSING_UPLOAD_FILE_PARAMETER unless file_name
|
21
|
+
options = validate_upload_options(options || {})
|
22
|
+
if options.is_a?(FalseClass)
|
23
|
+
raise ArgumentError, "Invalid Upload option"
|
24
|
+
else
|
25
|
+
headers = @req_obj.create_headers
|
26
|
+
payload = {multipart: true, file: file, fileName: file_name}.merge(options)
|
27
|
+
|
28
|
+
url = "#{URL::BASE_URL}#{URL::UPLOAD}"
|
29
|
+
@req_obj.request("post", url, headers, payload)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_details(file_id, options)
|
34
|
+
# Update file detail by file_id and options
|
35
|
+
|
36
|
+
unless (options.key? :tags) || (options.key? :custom_coordinates)
|
37
|
+
raise ArgumentError, UPDATE_DATA_MISSING
|
38
|
+
end
|
39
|
+
unless options.fetch(:tags, []).is_a?(Array)
|
40
|
+
raise ArgumentError, UPDATE_DATA_TAGS_INVALID
|
41
|
+
end
|
42
|
+
unless options.fetch(:custom_coordinates, "").is_a?(String)
|
43
|
+
raise ArgumentError, UPDATE_DATA_COORDS_INVALID
|
44
|
+
end
|
45
|
+
url = "#{URL::BASE_URL}/#{file_id}/details/"
|
46
|
+
headers = @req_obj.create_headers
|
47
|
+
payload = request_formatter(options)
|
48
|
+
@req_obj.request("patch", url, headers, payload.to_json)
|
49
|
+
end
|
50
|
+
|
51
|
+
def list(options)
|
52
|
+
# returns list of files on ImageKit Server
|
53
|
+
# :options dictionary of options
|
54
|
+
formatted_options = request_formatter(options)
|
55
|
+
raise KeyError(LIST_FILES_INPUT_MISSING) unless formatted_options.is_a?(Hash)
|
56
|
+
url = URL::BASE_URL
|
57
|
+
headers = @req_obj.create_headers.update({params: options})
|
58
|
+
@req_obj.request("get", url, headers, options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def details(file_identifier)
|
62
|
+
# Get detail of file by file_identifier
|
63
|
+
url = "#{URL::BASE_URL}/#{file_identifier}/details/"
|
64
|
+
headers = @req_obj.create_headers
|
65
|
+
@req_obj.request("get", url, headers)
|
66
|
+
end
|
67
|
+
|
68
|
+
def get_metadata(file_id)
|
69
|
+
# Get metadata of a file by file_id
|
70
|
+
url = "#{URL::BASE_URL}/#{file_id}/metadata"
|
71
|
+
@req_obj.request("get", url, @req_obj.create_headers)
|
72
|
+
end
|
73
|
+
|
74
|
+
def delete(file_id)
|
75
|
+
# Delete a file_id by file_id
|
76
|
+
url = "#{URL::BASE_URL}/#{file_id}"
|
77
|
+
headers = @req_obj.create_headers
|
78
|
+
@req_obj.request("delete", url, headers)
|
79
|
+
end
|
80
|
+
|
81
|
+
def batch_delete(file_ids)
|
82
|
+
url = "#{URL::BASE_URL}#{URL::BULK_FILE_DELETE}"
|
83
|
+
payload = {'fileIds': file_ids}
|
84
|
+
@req_obj.request("post", url, @req_obj.create_headers, payload.to_json)
|
85
|
+
end
|
86
|
+
|
87
|
+
def purge_cache(file_url)
|
88
|
+
|
89
|
+
# purges cache from server by file_url
|
90
|
+
|
91
|
+
url = "#{URL::BASE_URL}/purge"
|
92
|
+
payload = {'url': file_url}
|
93
|
+
@req_obj.request("post", url, @req_obj.create_headers, payload)
|
94
|
+
end
|
95
|
+
|
96
|
+
def purge_cache_status(request_id)
|
97
|
+
# This function is to get cache_status
|
98
|
+
url = "#{URL::BASE_URL}/purge/#{request_id}"
|
99
|
+
@req_obj.request("get", url, @req_obj.create_headers)
|
100
|
+
end
|
101
|
+
|
102
|
+
def get_metadata_from_remote_url(remote_file_url)
|
103
|
+
if remote_file_url == ""
|
104
|
+
raise ArgumentError, "remote_file_url is required"
|
105
|
+
end
|
106
|
+
url = "#{URL::REMOTE_METADATA_FULL_URL}?url=#{remote_file_url}"
|
107
|
+
@req_obj.request("get", url, @req_obj.create_headers)
|
108
|
+
end
|
109
|
+
|
110
|
+
def validate_upload_options(options)
|
111
|
+
|
112
|
+
# Validates upload value, checks if params are valid,
|
113
|
+
# changes snake to camel case which is supported by
|
114
|
+
# ImageKit server
|
115
|
+
|
116
|
+
|
117
|
+
response_list = []
|
118
|
+
options.each do |key, val|
|
119
|
+
if VALID_UPLOAD_OPTIONS.include?(key.to_s)
|
120
|
+
if val.is_a?(Array)
|
121
|
+
val = val.join(",")
|
122
|
+
end
|
123
|
+
if val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
124
|
+
val = val.to_s
|
125
|
+
end
|
126
|
+
options[key] = val
|
127
|
+
else
|
128
|
+
return false
|
129
|
+
end
|
130
|
+
end
|
131
|
+
request_formatter(options)
|
132
|
+
end
|
133
|
+
end
|