imagekitio 1.0.10 → 2.0.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +292 -82
  3. data/Rakefile +1 -1
  4. data/lib/active_storage/active_storage.rb +2 -0
  5. data/lib/active_storage/service/ik_file.rb +111 -0
  6. data/lib/active_storage/service/image_kit_io_service.rb +185 -0
  7. data/lib/carrierwave/carrierwave.rb +79 -0
  8. data/lib/carrierwave/storage/ik_file.rb +8 -7
  9. data/lib/carrierwave/storage/imagekit_store.rb +54 -51
  10. data/lib/carrierwave/support/uri_filename.rb +9 -7
  11. data/lib/imagekitio/api_service/bulk.rb +58 -0
  12. data/lib/imagekitio/api_service/custom_metadata_field.rb +52 -0
  13. data/lib/imagekitio/api_service/file.rb +162 -0
  14. data/lib/imagekitio/api_service/folder.rb +49 -0
  15. data/lib/imagekitio/base.rb +12 -0
  16. data/lib/imagekitio/client.rb +186 -0
  17. data/lib/imagekitio/configurable.rb +43 -0
  18. data/lib/imagekitio/constant.rb +36 -0
  19. data/lib/imagekitio/constants/default.rb +22 -0
  20. data/lib/imagekitio/constants/error.rb +69 -0
  21. data/lib/imagekitio/constants/file.rb +11 -0
  22. data/lib/imagekitio/constants/supported_transformation.rb +64 -0
  23. data/lib/imagekitio/constants/url.rb +14 -0
  24. data/lib/imagekitio/errors.rb +4 -0
  25. data/lib/imagekitio/railtie.rb +1 -1
  26. data/lib/imagekitio/request.rb +79 -0
  27. data/lib/imagekitio/sdk/version.rb +5 -0
  28. data/lib/imagekitio/url.rb +241 -0
  29. data/lib/imagekitio/utils/calculation.rb +44 -0
  30. data/lib/imagekitio/utils/formatter.rb +48 -0
  31. data/lib/imagekitio/utils/option_validator.rb +36 -0
  32. data/lib/imagekitio.rb +10 -83
  33. metadata +41 -15
  34. data/lib/imagekit/constants/defaults.rb +0 -20
  35. data/lib/imagekit/constants/errors.rb +0 -77
  36. data/lib/imagekit/constants/file.rb +0 -5
  37. data/lib/imagekit/constants/supported_transformation.rb +0 -57
  38. data/lib/imagekit/constants/url.rb +0 -9
  39. data/lib/imagekit/file.rb +0 -133
  40. data/lib/imagekit/imagekit.rb +0 -117
  41. data/lib/imagekit/resource.rb +0 -56
  42. data/lib/imagekit/sdk/version.rb +0 -5
  43. data/lib/imagekit/url.rb +0 -237
  44. data/lib/imagekit/utils/calculation.rb +0 -36
  45. data/lib/imagekit/utils/formatter.rb +0 -29
@@ -0,0 +1,185 @@
1
+ require_relative './ik_file'
2
+
3
+ if defined? Rails
4
+ # Overwrite the ActiveStorage::Downloader's open method and remove the file integrity check constraint method verify_integrity_of
5
+ class DownloaderExtension < ::ActiveStorage::Downloader
6
+ def open(key, checksum:, name: "ActiveStorage-", tmpdir: nil)
7
+ open_tempfile(name, tmpdir) do |file|
8
+ download key, file
9
+ # verify_integrity_of file, checksum: checksum
10
+ yield file
11
+ end
12
+ end
13
+ end
14
+
15
+ module ActiveStorageBlobExtension
16
+ def self.included(base)
17
+ base.class_eval do
18
+ before_update :check_metadata
19
+ before_destroy :remove_imagekit_file
20
+ # ActiveRecord::Blob class first destroy the record data and then calls the service.delete method with key
21
+ # as an argument. But the imagekit.io needs fileId to destroy the file which can be get from the metadata.
22
+ # So first destroy the remote file and then destroy the local blob record.
23
+ def remove_imagekit_file
24
+ service.class.delete_ik_file(self)
25
+ end
26
+
27
+ def remote_file_exist?
28
+ service.exist?(self.key)
29
+ end
30
+
31
+ def remote_file
32
+ return false unless remote_file_exist?
33
+
34
+ service.class.remote_file(self)
35
+ end
36
+
37
+ # Needs to reload the record to reflect updated remote meta data.
38
+ def check_metadata
39
+ self.reload
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ Rails.application.config.to_prepare do
46
+ ActiveStorage::Blob.send :include, ::ActiveStorageBlobExtension
47
+ end
48
+
49
+ module ActiveStorage
50
+ class Service::ImageKitIoService < Service
51
+ include ImageKitIo::Constantable
52
+
53
+ class << self
54
+ def delete_ik_file(blob)
55
+ ik_file(blob).delete
56
+ end
57
+
58
+ def remote_file(blob)
59
+ ik_file(blob)
60
+ end
61
+
62
+ def ik_file(blob)
63
+ self.new.send(:ik_file).new(blob.metadata)
64
+ end
65
+ end
66
+
67
+ def initialize(**options)
68
+ @options = options
69
+ end
70
+
71
+ def upload(key, io, checksum: nil, **options)
72
+ instrument :upload, key: key, checksum: checksum do
73
+ blob = storage_blob(key)
74
+ response = client.upload_file(file: io, file_name: blob.filename.to_s)
75
+ if response[:error].nil?
76
+ blob.update_columns(metadata: response[:response].transform_keys(&:to_sym))
77
+ end
78
+ end
79
+ end
80
+
81
+ def download(key, &block)
82
+ if block_given?
83
+ instrument :stream_file, key: key do
84
+ stream_file(key, &block)
85
+ end
86
+ else
87
+ instrument :download, key: key do
88
+ image_kit_file(key)
89
+ end
90
+ end
91
+ end
92
+
93
+ def download_chunk(key, range)
94
+ puts 'Not implemented download_chunk'
95
+ end
96
+
97
+ def delete(key)
98
+ instrument :delete, key: key do
99
+ # image kit file is already deleted on before blob destroy callback
100
+ key
101
+ end
102
+ end
103
+
104
+ def delete_prefixed(prefix)
105
+ # delete the variants files
106
+ puts 'Not implemented delete_prefixed'
107
+ end
108
+
109
+ def exist?(key)
110
+ image_kit_file(key).exist?
111
+ end
112
+
113
+ def url_for_direct_upload(key, **options)
114
+ instrument :url, key: key do |payload|
115
+ options.delete(:content_length)
116
+ options.delete(:checksum)
117
+ url = "#{constants.BASE_URL}#{constants.UPLOAD}"
118
+ generated_url = client.url(src: url)
119
+ payload[:url] = generated_url
120
+ generated_url
121
+ end
122
+ end
123
+
124
+ def headers_for_direct_upload(key, content_type:, checksum:, **options)
125
+ {
126
+ 'Content-Type' => content_type
127
+ }
128
+ end
129
+
130
+ def path_for(key)
131
+ image_kit_file(key).path
132
+ end
133
+
134
+ def url(key, filename: nil, content_type: '', **options)
135
+ image_kit_file(key).url
136
+ end
137
+
138
+ def open(*args, **options, &block)
139
+ DownloaderExtension.new(self).open(*args, **options, &block)
140
+ end
141
+
142
+ private
143
+
144
+ def private_url(key, expires_in:, filename:, disposition:, content_type:, **)
145
+ generate_url(key, expires_in: expires_in, filename: filename, disposition: disposition, content_type: content_type)
146
+ end
147
+
148
+ def generate_url(key, expires_in:, filename:, content_type:, disposition:)
149
+ filename = '/' + filename.to_s if filename.is_a? ActiveStorage::Filename
150
+ client.url(path: filename, url_endpoint: config.url_endpoint)
151
+ end
152
+
153
+ def client
154
+ ImageKitIo.client
155
+ end
156
+
157
+ def config
158
+ ImageKitIo.config
159
+ end
160
+
161
+ def storage_blob(key)
162
+ ActiveStorage::Blob.find_by_key(key)
163
+ end
164
+
165
+ def image_kit_file(key)
166
+ blob = storage_blob(key)
167
+ ik_file.new(blob.metadata)
168
+ end
169
+
170
+ def ik_file
171
+ ImageKiIo::ActiveStorage::IKFile
172
+ end
173
+
174
+ def stream_file(key, &download_block)
175
+ file_obj = image_kit_file(key)
176
+ block = proc { |response|
177
+ response.read_body do |chunk|
178
+ download_block.call(chunk) if download_block.present?
179
+ end
180
+ }
181
+ client.stream_file(file_url: file_obj.url, &block)
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,79 @@
1
+ require 'carrierwave'
2
+ require_relative './storage/imagekit_store'
3
+ require_relative './storage/ik_file'
4
+ require_relative './support/uri_filename'
5
+
6
+ module ImageKitIo
7
+ module CarrierWave
8
+ def self.included(base)
9
+ base.include InstanceMethods
10
+ base.class_eval do
11
+ configure do |config|
12
+ config.storage_engines[:imagekit_store] = 'ImageKitIo::CarrierWave::Storage::ImageKitStore'
13
+ end
14
+ end
15
+ base.storage :imagekit_store
16
+ end
17
+
18
+ module InstanceMethods
19
+ def initialize(*)
20
+ @imagekit = ImageKitIo.client
21
+ @options = {}
22
+ end
23
+
24
+ def filename
25
+ if options != nil
26
+ @options = options
27
+ end
28
+ folder = nil
29
+ begin
30
+ folder = store_dir
31
+ rescue
32
+ end
33
+
34
+ if folder != nil
35
+ @options[:folder] = folder
36
+ end
37
+
38
+ if self.file != nil
39
+ resp = @imagekit.upload_file(file: open(self.file.file, 'rb'), file_name: self.file.filename, **@options)
40
+ # ::File.delete(self.file.file)
41
+ res = resp[:response].to_json
42
+ if res != "null"
43
+ res
44
+ else
45
+ "{\"filePath\":\"\",\"url\":\"\",\"name\":\"\"}"
46
+ end
47
+ else
48
+ "{\"filePath\":\"\",\"url\":\"\",\"name\":\"\"}"
49
+ end
50
+ end
51
+
52
+ def fileId
53
+ JSON.parse(self.identifier)['fileId']
54
+ end
55
+
56
+ def blob
57
+ JSON.parse(self.identifier)
58
+ end
59
+
60
+ def url_with(opt)
61
+ path = JSON.parse(self.identifier)['filePath']
62
+ opt[:path] = path
63
+ url = @imagekit.url(opt)
64
+ end
65
+
66
+ def url
67
+ JSON.parse(self.identifier)['url']
68
+ end
69
+
70
+ def options
71
+ options = {}
72
+ end
73
+
74
+ def store_dir
75
+ store_dir = nil
76
+ end
77
+ end
78
+ end
79
+ end
@@ -1,17 +1,17 @@
1
- module CarrierWave
1
+ module ImageKitIo
2
+ module CarrierWave
2
3
  module Storage
3
4
  class IKFile
4
5
  # Initialize as required.
5
-
6
+
6
7
  def initialize(identifier)
7
8
  @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])
9
+ @imagekit = ImageKitIo.client
10
10
  end
11
11
 
12
- # Duck-type methods for CarrierWave::SanitizedFile.
12
+ # Duck-type methods for CarrierWave::SanitizedFile.
13
13
  def content_type
14
- "image/jpg"
14
+ "image/jpg"
15
15
  end
16
16
  def public_url
17
17
  @identifier['url']
@@ -33,7 +33,7 @@ module CarrierWave
33
33
  def delete
34
34
  # file_id=@identifier['fileId']
35
35
  begin
36
- @imagekit.delete_file(fileId)
36
+ @imagekit.delete_file(file_id: fileId)
37
37
  rescue
38
38
  fileId
39
39
  end
@@ -47,4 +47,5 @@ module CarrierWave
47
47
 
48
48
  end
49
49
 
50
+ end
50
51
  end
@@ -1,65 +1,68 @@
1
1
  require 'uri'
2
2
  require 'net/http'
3
3
  require 'base64'
4
- module CarrierWave
4
+
5
+ module ImageKitIo
6
+ module CarrierWave
5
7
  module Storage
6
- class ImageKitStore < Abstract
8
+ class ImageKitStore < ::CarrierWave::Storage::Abstract
7
9
 
8
- def initialize(*)
9
- super
10
- @cache_called = nil
11
- end
12
-
13
- def store!(file)
14
- file.delete
15
- end
10
+ def initialize(*)
11
+ super
12
+ @cache_called = nil
13
+ end
16
14
 
17
- def retrieve!(identifier)
18
-
19
- IKFile.new(identifier)
20
- end
15
+ def store!(file)
16
+ file.delete
17
+ end
21
18
 
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
19
+ def retrieve!(identifier)
33
20
 
34
- def retrieve_from_cache!(identifier)
35
- CarrierWave::SanitizedFile.new(::File.expand_path(uploader.cache_path(identifier), uploader.root))
36
- end
21
+ IKFile.new(identifier)
22
+ end
37
23
 
38
- def delete_dir!(path)
39
- if path
40
- begin
41
- Dir.rmdir(::File.expand_path(path, uploader.root))
42
- rescue Errno::ENOENT
43
- # Ignore: path does not exist
44
- rescue Errno::ENOTDIR
45
- # Ignore: path is not a dir
46
- rescue Errno::ENOTEMPTY, Errno::EEXIST
47
- # Ignore: dir is not empty
48
- end
49
- end
24
+ def cache!(new_file)
25
+ new_file.move_to(::File.expand_path(uploader.cache_path, uploader.root), uploader.permissions, uploader.directory_permissions, true)
26
+ rescue Errno::EMLINK, Errno::ENOSPC => e
27
+ raise(e) if @cache_called
28
+ @cache_called = true
29
+
30
+ # NOTE: Remove cached files older than 10 minutes
31
+ clean_cache!(600)
32
+
33
+ cache!(new_file)
34
+ end
35
+
36
+ def retrieve_from_cache!(identifier)
37
+ CarrierWave::SanitizedFile.new(::File.expand_path(uploader.cache_path(identifier), uploader.root))
38
+ end
39
+
40
+ def delete_dir!(path)
41
+ if path
42
+ begin
43
+ Dir.rmdir(::File.expand_path(path, uploader.root))
44
+ rescue Errno::ENOENT
45
+ # Ignore: path does not exist
46
+ rescue Errno::ENOTDIR
47
+ # Ignore: path is not a dir
48
+ rescue Errno::ENOTEMPTY, Errno::EEXIST
49
+ # Ignore: dir is not empty
50
+ end
50
51
  end
52
+ end
51
53
 
52
- def clean_cache!(seconds)
53
- Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), CarrierWave.root)).each do |dir|
54
- # generate_cache_id returns key formated TIMEINT-PID(-COUNTER)-RND
55
- time = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first.map(&:to_i)
56
- time = Time.at(*time)
57
- if time < (Time.now.utc - seconds)
58
- FileUtils.rm_rf(dir)
59
- end
60
- end
54
+ def clean_cache!(seconds)
55
+ Dir.glob(::File.expand_path(::File.join(uploader.cache_dir, '*'), CarrierWave.root)).each do |dir|
56
+ # generate_cache_id returns key formated TIMEINT-PID(-COUNTER)-RND
57
+ time = dir.scan(/(\d+)-\d+-\d+(?:-\d+)?/).first.map(&:to_i)
58
+ time = Time.at(*time)
59
+ if time < (Time.now.utc - seconds)
60
+ FileUtils.rm_rf(dir)
61
+ end
61
62
  end
62
-
63
63
  end
64
+
65
+ end
64
66
  end
65
- end
67
+ end
68
+ end
@@ -1,10 +1,12 @@
1
- module CarrierWave
1
+ module ImageKitIo
2
+ module CarrierWave
2
3
  module Support
3
- module UriFilename
4
- def self.filename(url)
5
- path = url.split('?').first
6
- URI.decode(path).gsub(%r{.*/(.*?$)}, '\1')
7
- end
4
+ module UriFilename
5
+ def self.filename(url)
6
+ path = url.split('?').first
7
+ URI.decode(path).gsub(%r{.*/(.*?$)}, '\1')
8
8
  end
9
+ end
9
10
  end
10
- end
11
+ end
12
+ end
@@ -0,0 +1,58 @@
1
+ require_relative '../constant'
2
+
3
+ module ImageKitIo
4
+ module ApiService
5
+ class Bulk
6
+ include Constantable
7
+
8
+ def initialize(req_obj)
9
+ @req_obj = req_obj
10
+ end
11
+
12
+ def job_status(job_id: nil)
13
+ if job_id == '' || job_id.nil?
14
+ raise ArgumentError, 'job_id is required'
15
+ end
16
+ url = "#{constants.BULK_BASE_URL}/#{job_id}"
17
+ payload = { 'jobId': job_id }
18
+ @req_obj.request('get', url, @req_obj.create_headers, payload)
19
+ end
20
+
21
+ def add_tags(file_ids: [], tags: [])
22
+ if file_ids.empty? || tags.empty?
23
+ raise ArgumentError, 'Parameters are required'
24
+ end
25
+ url = "#{constants.BASE_URL}/addTags"
26
+ payload = { 'fileIds': file_ids, 'tags': tags }.to_json
27
+ @req_obj.request('post', url, @req_obj.create_headers, payload)
28
+ end
29
+
30
+ def remove_tags(file_ids: [], tags: [])
31
+ if file_ids.empty? || tags.empty?
32
+ raise ArgumentError, 'Parameters are required'
33
+ end
34
+ url = "#{constants.BASE_URL}/removeTags"
35
+ payload = { 'fileIds': file_ids, 'tags': tags }.to_json
36
+ @req_obj.request('post', url, @req_obj.create_headers, payload)
37
+ end
38
+
39
+ def remove_ai_tags(file_ids: [], ai_tags: [])
40
+ if file_ids.empty? || ai_tags.empty?
41
+ raise ArgumentError, 'Parameters are required'
42
+ end
43
+ url = "#{constants.BASE_URL}/removeAITags"
44
+ payload = { 'fileIds': file_ids, 'AITags': ai_tags }.to_json
45
+ @req_obj.request('post', url, @req_obj.create_headers, payload)
46
+ end
47
+
48
+ def remove_files(file_ids: [])
49
+ if file_ids.empty?
50
+ raise ArgumentError, 'File ids are required'
51
+ end
52
+ url = "#{constants.BASE_URL}#{constants.BULK_FILE_DELETE}"
53
+ payload = {'fileIds': file_ids}.to_json
54
+ @req_obj.request("post", url, @req_obj.create_headers, payload)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,52 @@
1
+ require_relative '../utils/option_validator'
2
+ require_relative '../constant'
3
+
4
+ module ImageKitIo
5
+ module ApiService
6
+ class CustomMetadataField
7
+ include Utils::OptionValidator
8
+ include Constantable
9
+
10
+ def initialize(req_obj)
11
+ @req_obj = req_obj
12
+ end
13
+
14
+ def create(name: nil, label: nil, schema: nil)
15
+ if name == '' || name.nil? || label == '' || label.nil? || schema == '' || schema.nil?
16
+ raise ArgumentError, 'Parameters required'
17
+ end
18
+ unless schema.is_a?(Hash)
19
+ raise ArgumentError, 'Schema must be hash object'
20
+ end
21
+ url = "#{constants.API_BASE_URL}/customMetadataFields"
22
+ payload = { 'name': name, 'label': label, 'schema': schema }.to_json
23
+ @req_obj.request('post', url, @req_obj.create_headers, payload)
24
+ end
25
+
26
+ def list(**options)
27
+ url = "#{constants.API_BASE_URL}/customMetadataFields"
28
+ payload = request_formatter(options || {})
29
+ @req_obj.request('get', url, @req_obj.create_headers, payload)
30
+ end
31
+
32
+ def update(id: nil, label: nil, schema: nil)
33
+ if id == '' || id.nil?
34
+ raise ArgumentError, 'id is required'
35
+ end
36
+ url = "#{constants.API_BASE_URL}/customMetadataFields/#{id}"
37
+ payload = {}
38
+ payload = payload.merge({ 'label': label }) unless label.nil?
39
+ payload = payload.merge({ 'schema': label }) unless schema.nil?
40
+ @req_obj.request('patch', url, @req_obj.create_headers, payload.to_json)
41
+ end
42
+
43
+ def delete(id: nil)
44
+ if id == '' || id.nil?
45
+ raise ArgumentError, 'id is required'
46
+ end
47
+ url = "#{constants.API_BASE_URL}/customMetadataFields/#{id}"
48
+ @req_obj.request('delete', url, @req_obj.create_headers)
49
+ end
50
+ end
51
+ end
52
+ end