balloon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,98 @@
1
+ require 'mini_magick'
2
+
3
+ module Balloon
4
+ module Processing
5
+ extend ActiveSupport::Concern
6
+
7
+ def resize_with_string(file)
8
+ width, height = "", ""
9
+ oranginl_img = MiniMagick::Image.open(file.path)
10
+ auto_orient!(oranginl_img, file.path)
11
+ if self.respond_to?(:uploader_size) && !(store_storage.to_s == "upyun" && upyun_is_image)
12
+ uploader_size.each do |s, o|
13
+ img = MiniMagick::Image.open(file.path)
14
+ raise ProcessError, "process error" unless img
15
+ width = img[:width]
16
+ height = img[:height]
17
+ new_img = resize(img, o)
18
+ new_img.write File.join(cache_path, "#{file.basename}_#{s}.#{file.extension}")
19
+ end
20
+ end
21
+ return {width: oranginl_img[:width], height: oranginl_img[:height]}
22
+ end
23
+
24
+ def resize(image, size)
25
+ width, height, symbol = size[:width], size[:height], size[:symbol]
26
+ if !symbol.empty? || width.match(/\%/) || height.match(/\%/)
27
+ if width == height
28
+ image = shave(image)
29
+ image.resize "#{width}"
30
+ else
31
+ image.resize "#{width}x#{height}#{symbol}"
32
+ end
33
+ else
34
+ if width == height
35
+ image = shave(image)
36
+ value = (width.to_f / image[:width].to_f) * 100
37
+ image.resize "#{value}%"
38
+ else
39
+ if width.empty?
40
+ value = (height.to_f / image[:height].to_f) * 100
41
+ image.resize "#{value}%"
42
+ elsif height.empty?
43
+ value = (width.to_f / image[:width].to_f) * 100
44
+ image.resize "#{value}%"
45
+ else
46
+ image.resize "#{width}x#{height}"
47
+ end
48
+ end
49
+ end
50
+ return image
51
+ end
52
+
53
+ def shave(image)
54
+ w, h = image[:width], image[:height]
55
+ if w > h
56
+ shave_off = ((w - h) / 2).round
57
+ image.shave "#{shave_off}x0"
58
+ else
59
+ shave_off = ((h - w) / 2).round
60
+ image.shave "0x#{shave_off}"
61
+ end
62
+ return image
63
+ end
64
+
65
+ def auto_orient!(img, file)
66
+ if img["exif:orientation"] == "6"
67
+ img.auto_orient
68
+ img.write file
69
+ end
70
+ end
71
+
72
+ # parseing the size string
73
+ #
74
+ # @return [Hash] the options for string
75
+ module ClassMethods
76
+ def parsing_size_string(size)
77
+ symbol = ""
78
+ symbol_regex = /[^\d|\!|\>|\<|\%|x|X]/
79
+ if size.include?('x')
80
+ if has_symbol = size.match(/[\!|\>|\<]/)
81
+ symbol = has_symbol[0]
82
+ size_option = size[0, 7].split("x")
83
+ else
84
+ size_option = size.split("x")
85
+ end
86
+ width, height = size_option
87
+ else
88
+ width, height = size, size
89
+ end
90
+ width = width || ""
91
+ width = width.match(symbol_regex) ? "" : width
92
+ height = height || ""
93
+ height = height.match(symbol_regex) ? "" : height
94
+ return { width: width, height: height, symbol: symbol }
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,62 @@
1
+ module Balloon
2
+ module Storage
3
+ class File < Balloon::Storage::Store
4
+ def store!
5
+ _store_path = store_path
6
+
7
+ if !::File.exists? _store_path
8
+ FileUtils.mkdir_p _store_path
9
+ FileUtils.chmod_R @uploader.dir_permissions.to_i, _store_path
10
+ end
11
+
12
+ original_file = set_upload_name
13
+ store_original_file = ::File.join _store_path, original_file
14
+ cache_original_file = ::File.join @uploader.cache_path, @uploader.info[:filename]
15
+ FileUtils.mv cache_original_file, store_original_file
16
+
17
+ if @uploader.respond_to?(:uploader_size)
18
+ @uploader.uploader_size.each do |s, o|
19
+ store_file = ::File.join _store_path, set_upload_name(s)
20
+ cache_file = ::File.join @uploader.cache_path, @uploader.info[:basename]+ "_#{s}"+"."+ @uploader.info[:extension]
21
+ FileUtils.mv cache_file, store_file
22
+ end
23
+ end
24
+ return { filename: original_file, basename: store_name}
25
+ end
26
+
27
+ def retrieve!(size_name = nil)
28
+ return "" if !upload_file
29
+ path = ::File.join upload_dir, store_filename(size_name)
30
+ return "/" + path if @uploader.asset_host.nil?
31
+ @uploader.asset_host + "/" + path
32
+ end
33
+
34
+ def delete!
35
+ return false if !upload_file
36
+ path = ::File.join store_path, store_filename
37
+ FileUtils.rm(path) if ::File.exists?(path)
38
+ if @uploader.respond_to?(:uploader_size)
39
+ @uploader.uploader_size.each do |s, o|
40
+ path = ::File.join store_path, store_filename(s)
41
+ FileUtils.rm(path) if ::File.exists?(path)
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def store_filename(size_name = nil)
49
+ extension = upload_file[:extension].blank? ? "" : "." + upload_file[:extension]
50
+ if size_name.nil?
51
+ upload_file[:basename] + extension
52
+ else
53
+ upload_file[:basename] + "_" + size_name.to_s + extension
54
+ end
55
+ end
56
+
57
+ def store_path
58
+ ::File.expand_path ::File.join(@uploader.root, @uploader.store_dir, upload_dir)
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,84 @@
1
+ module Balloon
2
+ module Storage
3
+ class Store
4
+ def initialize(uploader)
5
+ @uploader = uploader
6
+ end
7
+
8
+ def store!; end
9
+
10
+ def retrieve!(size_name = nil); end
11
+
12
+ def upload_file
13
+ file_info = @uploader.info
14
+ return {} if file_info.nil?
15
+ basename = file_info[:basename] || ""
16
+ extension = file_info[:extension] || ""
17
+ { basename: basename, extension: extension }
18
+ end
19
+
20
+ def upload_dir
21
+ @uploader.respond_to?(:uploader_dir) ? @uploader.uploader_dir : @uploader.uploader_name
22
+ end
23
+
24
+ def store_name
25
+ return upload_file[:basename] if !@uploader.respond_to?(:uploader_name_format)
26
+ name_format = @uploader.uploader_name_format
27
+ name = name_format[:name]
28
+ if name_format[:format].to_s == "downcase"
29
+ name = name.downcase
30
+ elsif name_format[:format].to_s == "upcase"
31
+ name = name.upcase
32
+ else
33
+ name
34
+ end
35
+ end
36
+
37
+ def set_upload_name(size_name = nil )
38
+ if size_name
39
+ store_name + "_#{size_name.to_s}" + "." + upload_file[:extension]
40
+ else
41
+ store_name + "." + upload_file[:extension]
42
+ end
43
+ end
44
+
45
+ def connection
46
+ options = self.class.get_option(self)
47
+ basic = self.class.get_basic_auth(self)
48
+ token = self.class.token_auth
49
+ conn = Http::Client.new(options[:url]) do |builder|
50
+ builder.headers = options[:headers]
51
+ builder.basic_auth(basic[:user], basic[:password]) if !basic.nil?
52
+ builder.token_auth(self, token) if !token.nil?
53
+ end
54
+ return conn
55
+ end
56
+
57
+ class << self
58
+ def conn_option(&block)
59
+ return @option_proc unless block_given?
60
+ @option_proc = block
61
+ end
62
+
63
+ def get_option(klass)
64
+ klass.instance_eval(&conn_option)
65
+ end
66
+
67
+ def basic_auth(&block)
68
+ return @basic_proc unless block_given?
69
+ @basic_proc = block
70
+ end
71
+
72
+ def get_basic_auth(klass)
73
+ return nil if basic_auth.nil?
74
+ klass.instance_eval(&basic_auth)
75
+ end
76
+
77
+ def token_auth(&block)
78
+ return @token_proc unless block_given?
79
+ @token_proc = block
80
+ end
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,91 @@
1
+ module Balloon
2
+ module Storage
3
+ class Upyun < Balloon::Storage::Store
4
+
5
+ conn_option do
6
+ {
7
+ url: conn_url,
8
+ headers: conn_headers,
9
+ timeout: @uploader.upyun_timeout
10
+ }
11
+ end
12
+
13
+ token_auth do |method, path, size, date|
14
+ "encode_canonical('#{method}', '#{path}', #{size}, '#{date}')"
15
+ end
16
+
17
+ def store!
18
+ _store_path = store_path
19
+ original_file = set_upload_name
20
+ store_original_file = ::File.join _store_path, original_file
21
+ cache_original_file = ::File.join @uploader.cache_path, @uploader.info[:filename]
22
+ file = ::File.new cache_original_file
23
+ response = connection.put(store_original_file, file.read, file.size)
24
+ raise "Connection errors" if response.nil?
25
+
26
+ if !@uploader.upyun_is_image && @uploader.respond_to?(:uploader_size)
27
+ @uploader.uploader_size.each do |s, o|
28
+ store_file = ::File.join _store_path, set_upload_name(s)
29
+ cache_file = ::File.join @uploader.cache_path, @uploader.info[:basename]+ "_#{s}"+"."+ @uploader.info[:extension]
30
+ file = ::File.new cache_file
31
+ connection.put(store_file, file.read, file.size)
32
+ end
33
+ end
34
+
35
+ return { filename: original_file, basename: store_name }
36
+ end
37
+
38
+ def retrieve!(size_name = nil)
39
+ if !@uploader.upyun_is_image || size_name.nil?
40
+ path = ::File.join upload_dir, store_filename(size_name)
41
+ @uploader.upyun_domain + "/" + path
42
+ else
43
+ filename = store_filename + @uploader.upyun_thumb_symbol + size_name.to_s
44
+ path = ::File.join upload_dir, filename
45
+ @uploader.upyun_domain + "/" + path
46
+ end
47
+ end
48
+
49
+ def delete!
50
+ _store_path = store_path
51
+ store_original_file = ::File.join _store_path, store_filename
52
+ response = connection.delete(store_original_file)
53
+ if !@uploader.upyun_is_image && @uploader.respond_to?(:uploader_size)
54
+ @uploader.uploader_size.each do |s, o|
55
+ store_file = ::File.join _store_path, store_filename(s)
56
+ connection.delete(store_file)
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def encode_canonical(method, path, size, date)
64
+ options = []
65
+ options << method
66
+ options << path
67
+ options << date
68
+ options << size
69
+ options << "#{Digest::MD5.hexdigest(@uploader.upyun_password)}"
70
+ "UpYun #{@uploader.upyun_username}:#{Digest::MD5.hexdigest(options.join("&"))}"
71
+ end
72
+
73
+ def store_filename(size_name = nil)
74
+ return upload_file[:basename] + "." + upload_file[:extension] if size_name == nil
75
+ upload_file[:basename] + "_" + size_name.to_s + "." + upload_file[:extension]
76
+ end
77
+
78
+ def conn_url
79
+ @uploader.upyun_api_host || "http://v0.api.upyun.com"
80
+ end
81
+
82
+ def conn_headers
83
+ @uploader.upyun_headers.merge({ 'Mkdir' => 'true', 'Expect' => '', 'Date' => Time.now.httpdate })
84
+ end
85
+
86
+ def store_path
87
+ ::File.join("/", @uploader.upyun_bucket, upload_dir)
88
+ end
89
+ end
90
+ end
91
+ end
data/lib/balloon/up.rb ADDED
@@ -0,0 +1,100 @@
1
+ module Balloon
2
+ module Up
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Balloon::Uploader
7
+ include Balloon::Validate
8
+ end
9
+
10
+ module ClassMethods
11
+ def uploader(name, db = nil)
12
+
13
+ before_create :uploader_save
14
+
15
+ class_eval <<-RUBY
16
+ def #{name}=(file)
17
+ save_to_cache(file)
18
+ rescue DownloadError => e
19
+ @download_error = e
20
+ rescue ProcessError => e
21
+ @process_error = e
22
+ end
23
+
24
+ def #{name}
25
+ @info
26
+ end
27
+
28
+ def uploader_save
29
+ return if info.nil?
30
+ set_storage_engine
31
+ store_info = storage_engine.store!
32
+ @info[:filename] = store_info[:filename]
33
+ @info[:basename] = store_info[:basename]
34
+ end
35
+
36
+ def uploader_name
37
+ "#{name}".pluralize
38
+ end
39
+ RUBY
40
+
41
+ set_keyword if db
42
+
43
+ validates_download_of name
44
+ end
45
+
46
+ def set_keyword
47
+ if defined?(MongoMapper)
48
+ key :file_name, String
49
+ key :width, Integer
50
+ key :height, Integer
51
+ key :content_type, String
52
+ key :file_size, Integer
53
+ key :storage, String
54
+ key :created_at
55
+ elsif defined?(Mongoid)
56
+ field :file_name, type: String
57
+ field :width, type: Integer
58
+ field :height, type: Integer
59
+ field :content_type, type: String
60
+ field :file_size, type: String
61
+ field :storage, type: String
62
+ field :created_at
63
+ end
64
+
65
+ before_create :save_db
66
+ after_destroy :uploader_delete
67
+
68
+ class_eval <<-RUBY
69
+ def save_db
70
+ return if info.nil?
71
+ self.file_name = info[:filename]
72
+ self.content_type = info[:mime_type]
73
+ self.file_size = info[:size]
74
+ self.storage = store_storage.to_s
75
+ self.width = info[:width]
76
+ self.height = info[:height]
77
+ end
78
+
79
+ def url(size_name = nil)
80
+ return "" if !respond_to?(:file_name) || file_name.nil?
81
+ extension = self.file_name.to_s.match(%r"(?!\\.{1})\\w{2,}$")
82
+ basename = self.file_name.to_s.gsub(%r"\\.{1}\\w{2,}$",'')
83
+ @info = { basename: basename, extension: extension.to_s }
84
+ set_storage_engine
85
+ storage_engine.retrieve!(size_name)
86
+ end
87
+
88
+ def uploader_delete
89
+ return if !respond_to?(:file_name) || file_name.nil?
90
+ extension = self.file_name.to_s.match(%r"(?!\\.{1})\\w{2,}$")
91
+ basename = self.file_name.to_s.gsub(%r"\\.{1}\\w{2,}$",'')
92
+ @info = { basename: basename, extension: extension.to_s }
93
+ set_storage_engine
94
+ storage_engine.delete!
95
+ end
96
+ RUBY
97
+ end
98
+ end #ClassMethods
99
+ end #Up
100
+ end
@@ -0,0 +1,90 @@
1
+ module Balloon
2
+ module Uploader
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ include Balloon::Configuration
7
+ include Balloon::Processing
8
+ include Balloon::Cache
9
+ include Balloon::Download
10
+ attr_accessor :file
11
+ attr_reader :storage_engine
12
+ attr_reader :info
13
+ attr_accessor :download_error, :process_error
14
+ end
15
+
16
+ def set_storage_engine
17
+ @storage_engine = eval(Balloon::Base::STORAGE_EGINE[store_storage.to_sym]).new(self) if !respond_to?(:@storage_engine)
18
+ end
19
+
20
+ def save_to_cache(up_file)
21
+ uploader_file = up_file.is_a?(String) && up_file.include?("://") ? down_url(up_file) : up_file
22
+
23
+ uploader_file_ext = Balloon::FileExtension.new(uploader_file)
24
+ file_mime_type = uploader_file_ext.mime_type
25
+
26
+ if self.respond_to?(:uploader_mimetype_white)
27
+ if !uploader_mimetype_white.include?(file_mime_type)
28
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
29
+ end
30
+ elsif self.respond_to?(:uploader_mimetype_black)
31
+ if !uploader_mimetype_black.include?(file_mime_type)
32
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
33
+ end
34
+ end
35
+
36
+ generate_cache_directory
37
+ up_file = uploader_file_ext.save_to cache_path, permissions
38
+ uploader_file = up_file
39
+ img = resize_with_string up_file
40
+ @info = {
41
+ width: img[:width],
42
+ height: img[:height],
43
+ size: up_file.size,
44
+ mime_type: up_file.mime_type,
45
+ filename: up_file.filename,
46
+ basename: up_file.basename,
47
+ extension: up_file.extension
48
+ }
49
+ end
50
+
51
+ def url(size_name = nil); end
52
+
53
+ module ClassMethods
54
+ def uploader_dir(name)
55
+ define_method "uploader_dir" do; name; end
56
+ end
57
+
58
+ def uploader_size(options)
59
+ list = {}
60
+
61
+ if options.is_a?(Hash)
62
+ options.each do |key, value|
63
+ list[key] = parsing_size_string(value)
64
+ end
65
+ else
66
+ list[:orignal] = parsing_size_string options
67
+ end
68
+
69
+ define_method "uploader_size" do; list; end
70
+ end
71
+
72
+ def uploader_name_format(info)
73
+ define_method "uploader_name_format" do
74
+ name = info[:name].nil? ? info[:name] : info[:name].call(self)
75
+ { name: name, format: info[:format] }
76
+ end
77
+ end
78
+
79
+ def uploader_mimetype_white(list)
80
+ raise "just choise one method" if respond_to?(:uploader_mime_type_black)
81
+ define_method "uploader_mimetype_white" do; list; end
82
+ end
83
+
84
+ def uploader_mimetype_black(list)
85
+ raise "just choise one method" if respond_to?(:uploader_mime_type_black)
86
+ define_method "uploader_mimetype_black" do; list; end
87
+ end
88
+ end
89
+ end #Uploader
90
+ end