balloon 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,50 @@
1
+ require 'faraday'
2
+ require 'mime/types'
3
+
4
+ module Balloon
5
+ module Download
6
+ extend ActiveSupport::Concern
7
+
8
+ def down_url(uri)
9
+ connection = ::Faraday.new
10
+ response = connection.get(uri)
11
+ generate_down_cache_directory
12
+ path = File.join down_cache_path, generate_down_id
13
+
14
+ if response.status != 200
15
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.response_error")
16
+ end
17
+
18
+ if content_type = MIME::Types[response.headers["content-type"]][0]
19
+ mime_type = content_type.content_type
20
+ if self.respond_to?(:uploader_mimetype_white)
21
+ if !uploader_mimetype_white.include?(mime_type)
22
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
23
+ end
24
+ elsif self.respond_to?(:uploader_mimetype_black)
25
+ if !uploader_mimetype_black.include?(mime_type)
26
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.down_mime_error")
27
+ end
28
+ end
29
+ end
30
+
31
+ File.open(path, "wb") do |f|
32
+ f.write(response.body)
33
+ end
34
+
35
+ return path
36
+ rescue Faraday::Error::ConnectionFailed => e
37
+ raise Balloon::DownloadError, I18n.translate(:"errors.messages.connection_failed")
38
+ rescue Faraday::Error::TimeoutError => e
39
+ raise Ballloon::DownloadError, I18n.translate(:"errors.messages.timeout_error")
40
+ end
41
+
42
+ private
43
+
44
+ def generate_down_id
45
+ now = Time.now
46
+ "#{now.to_i}#{now.usec.to_s[0, 5]}".to_i.to_s(16)
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,5 @@
1
+ module Balloon
2
+ class UploadError < StandardError; end
3
+ class DownloadError < UploadError; end
4
+ class ProcessError < UploadError; end
5
+ end
@@ -0,0 +1,187 @@
1
+ require 'mime/types'
2
+ require 'pathname'
3
+
4
+ module Balloon
5
+ # This class is file Extension for ruby class
6
+ #
7
+ # @param[File, UploadFile, Hash, String, StringIO] file
8
+ #
9
+ # @example
10
+ #
11
+ # file = FileExtension.new(file)
12
+ # file.path
13
+ # file.filename
14
+ # file.basename
15
+ # file.mime_type
16
+ # file.extension
17
+ # file.read
18
+ #
19
+
20
+ class FileExtension
21
+ SANITIZE_REGEX = /[^a-zA-Z0-9\.]|[\^]/
22
+
23
+ FILENAME_REGEX = [ /\A(.+)\.(tar\.([glxb]?z|bz2))\z/, /\A(.+)\.([^\.]+)\z/ ]
24
+
25
+ IMAGE_REGEX = [
26
+ ["GIF8", "image/gif"],
27
+ ["\x89PNG", "image/png"],
28
+ ["\xff\xd8\xff\xe0\x00\x10JFIF", "image/jpeg"],
29
+ ["\xff\xd8\xff\xe1(.*){2}Exif", "image/jpeg"]
30
+ ]
31
+
32
+ IMAGE_EXT_LIST = {
33
+ "image/gif" => "gif",
34
+ "image/jpeg" => "jpg",
35
+ "image/png" => "png"
36
+ }
37
+
38
+ def initialize(file, mime_type = nil)
39
+ if file.is_a?(Hash)
40
+ @file = file["tempfile"] || file[:tempfile]
41
+ @original_filename = file["filename"] || file[:filename]
42
+ @mime_type = file["content_type"] || file[:content_type]
43
+ else
44
+ @file = file
45
+ @original_filename = nil
46
+ @mime_type = mime_type
47
+ end
48
+ end
49
+
50
+ # Get real path with uploaded file
51
+ #
52
+ # @return [String] file path
53
+ def path
54
+ return "" if @file.blank?
55
+ if @file.is_a?(String) || @file.is_a?(Pathname)
56
+ File.expand_path(@file)
57
+ elsif @file.respond_to?(:path)
58
+ File.expand_path(@file.path)
59
+ else
60
+ ""
61
+ end
62
+ end
63
+
64
+ # Get original filename with uploaded file
65
+ #
66
+ # @return [String] file original filename
67
+ def original_filename
68
+ return @original_filename if @original_filename
69
+ if @file && @file.respond_to?(:original_filename)
70
+ @file.original_filename
71
+ elsif !path.blank?
72
+ File.basename(path)
73
+ else
74
+ ""
75
+ end
76
+ end
77
+
78
+ # Get filename with uploaded file
79
+ #
80
+ # @return [string] the real filename
81
+ def filename
82
+ return "" if original_filename.blank?
83
+ sanitize(original_filename)
84
+ end
85
+
86
+ def basename
87
+ return "" if filename.blank?
88
+ split_extension(filename)[0]
89
+ end
90
+
91
+ def extension
92
+ ext_name = split_extension(filename)[1] if !filename.blank?
93
+ return ext_name if !ext_name.blank?
94
+ return IMAGE_EXT_LIST[mime_type]
95
+ end
96
+
97
+ def mime_type
98
+ return get_mime_type(MIME::Types[@mime_type]) if @mime_type
99
+ ext_name = split_extension(filename)[1] if !filename.blank?
100
+ return get_mime_type(MIME::Types.type_for(ext_name)) if !ext_name.blank?
101
+ if type = read_mime_type then return type end
102
+ if type = command_mime_type then return type end
103
+ end
104
+
105
+ def size
106
+ return 0 if @file.blank?
107
+ if @file.is_a?(String)
108
+ exists? ? File.size(path) : 0
109
+ elsif @file.respond_to?(:size)
110
+ @file.size
111
+ else
112
+ 0
113
+ end
114
+ end
115
+
116
+ def empty?
117
+ @file.nil? || self.size.nil? || ( self.size.zero? && !self.exists? )
118
+ end
119
+
120
+ def exists?
121
+ return File.exists?(self.path) if !path.empty?
122
+ return false
123
+ end
124
+
125
+ def read(count = nil)
126
+ return "" if empty?
127
+ if exists? && @file.is_a?(String)
128
+ File.open(@file, "rb") {|file| file.read(count) }
129
+ elsif @file.respond_to?(:read)
130
+ @file.read(count)
131
+ else
132
+ ""
133
+ end
134
+ end
135
+
136
+
137
+ # @todo What Change basename add extension
138
+ def save_to(new_path, permissions = nil, directory_permission = nil)
139
+ new_path = File.expand_path new_path
140
+ new_path = File.join new_path, basename + "." + extension
141
+
142
+ if exists?
143
+ FileUtils.cp(path, new_path) unless new_path == path
144
+ else
145
+ File.open(new_path, "wb"){ |f| f.write(read) }
146
+ end
147
+ File.chmod(permissions, new_path) if permissions
148
+ self.class.new(new_path)
149
+ end
150
+
151
+ private
152
+
153
+ def sanitize(name)
154
+ name = name.gsub("\\", "/")
155
+ name = name.gsub(SANITIZE_REGEX, "_")
156
+ name = "_#{name}" if name =~ /\A\.+\z/
157
+ name = "unnamed" if name.size == 0
158
+ #name = name.downcase
159
+ return name.mb_chars.to_s
160
+ end
161
+
162
+ def split_extension(filename)
163
+ FILENAME_REGEX.each do |regexp|
164
+ return $1, $2 if filename =~ regexp
165
+ end
166
+ return filename, ""
167
+ end
168
+
169
+ def get_mime_type(mime_type)
170
+ mime_type.first.content_type if !mime_type.empty?
171
+ end
172
+
173
+ def read_mime_type
174
+ content = read(10)
175
+ return if content.blank?
176
+ IMAGE_REGEX.each do |regexp|
177
+ return regexp[1] if content =~ %r"^#{regexp[0].force_encoding("binary")}"
178
+ end
179
+ return nil
180
+ end
181
+
182
+ def command_mime_type
183
+ content = `file #{path} --mime-type`.gsub("\n", '')
184
+ content.split(':')[1].strip if content
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,91 @@
1
+ require 'faraday'
2
+
3
+ module Balloon
4
+ module Http
5
+ class Client
6
+
7
+ attr_reader :url
8
+
9
+ attr_reader :login, :pass
10
+
11
+ attr_reader :klass, :token
12
+
13
+ attr_accessor :headers
14
+
15
+ attr_accessor :options
16
+
17
+ attr_accessor :connection
18
+
19
+ attr_accessor :conn_build
20
+
21
+ def initialize(uri = nil, options = nil, &block)
22
+ @url = uri
23
+ yield self if block_given?
24
+ end
25
+
26
+ def builder(&block)
27
+ @conn_build = block
28
+ end
29
+
30
+ def url=(uri)
31
+ @conn = nil
32
+ @url = uri
33
+ end
34
+
35
+ def basic_auth(login, pass)
36
+ @login = login
37
+ @pass = pass
38
+ end
39
+
40
+ def token_auth(klass, token)
41
+ @klass = klass
42
+ @token = token
43
+ end
44
+
45
+ def connection
46
+ @connection ||= begin
47
+ conn = Faraday.new(url: url)
48
+ conn.basic_auth(login, pass) if login
49
+ conn.build do |b|
50
+ conn_build.call(b)
51
+ end if conn_build
52
+ conn
53
+ end
54
+ end
55
+
56
+ def request(verb, uri, query={}, size = nil)
57
+ headers['Authorization'] = klass.instance_eval(token.call(verb.to_s.upcase, uri, size, headers['Date'])) if token
58
+ verb == :get ? query_get = query : query_post = query
59
+ uri = connection.build_url(uri, query_get)
60
+ response = connection.run_request(verb, uri, query_post, headers) do |request|
61
+ yield request if block_given?
62
+ end
63
+ response = Response.new(response)
64
+ case response.status
65
+ when 301, 302, 303, 307
66
+ request(verb, response.headers['location'], query)
67
+ when 200..299, 300..399
68
+ response
69
+ end
70
+ end
71
+
72
+ def get(uri, query = {}, &block)
73
+ request(:get, uri, query, 0, &block)
74
+ end
75
+
76
+ def post(uri, query = {}, size = nil, &block)
77
+ size = size || 0
78
+ request(:post, uri, query, size,&block)
79
+ end
80
+
81
+ def put(uri, query = {}, size = nil, &block)
82
+ size = size || 0
83
+ request(:put, uri, query, size, &block)
84
+ end
85
+
86
+ def delete(uri, &block)
87
+ request(:delete, uri, nil, 0, &block)
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,71 @@
1
+ module Balloon
2
+ module Http
3
+ class Response
4
+ attr_reader :response
5
+
6
+ CONTENT_TYPE = {
7
+ 'application/json' => :json,
8
+ 'application/x-www-form-urlencoded' => :html,
9
+ 'text/html' => :html,
10
+ 'text/javascript' => :json
11
+ }
12
+
13
+ PARSERS = {
14
+ :json => lambda{ |body| MultiJson.respond_to?(:adapter) ? MultiJson.load(body) : MultiJson.decode(body) rescue body},
15
+ :html => lambda{ |body| Nokogiri::HTML(body)}
16
+ }
17
+
18
+ def initialize(response)
19
+ @response = response
20
+ end
21
+
22
+ def headers
23
+ response.headers
24
+ end
25
+
26
+ def body
27
+ decode(response.body)
28
+ end
29
+
30
+ def decode(body)
31
+ return '' if !body
32
+ return body if json?
33
+ charset = body.match(/charset\s*=[\s|\W]*([\w-]+)/)
34
+ if charset[1].downcase != "utf-8"
35
+ begin
36
+ body.encode! "utf-8", charset[1], {:invalid => :replace}
37
+ rescue
38
+ body
39
+ end
40
+ else
41
+ body
42
+ end
43
+ end
44
+
45
+ def status
46
+ response.status
47
+ end
48
+
49
+ # Attempts to determine the content type of the response.
50
+ def content_type
51
+ ((response.headers.values_at('content-type', 'Content-Type').compact.first || '').split(';').first || '').strip
52
+ end
53
+
54
+ def json?
55
+ CONTENT_TYPE[content_type] == :json || !response.body.match(/\<html/)
56
+ end
57
+
58
+ def parser
59
+ type = CONTENT_TYPE[content_type]
60
+ type = :json if type == :html && !response.body.match(/\<html/)
61
+ return type
62
+ end
63
+
64
+ def parsed
65
+ return nil unless CONTENT_TYPE.key?(content_type)
66
+ return nil unless PARSERS.key?(parser)
67
+ @parsed ||= PARSERS[parser].call(body)
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,33 @@
1
+ if defined?(Rails)
2
+ module Balloon
3
+ class Railtie < Rails::Railtie
4
+ initializer "balloon set path" do
5
+ Balloon.root = Rails.root.to_s
6
+ end
7
+
8
+ initializer "Baloon.configure_rails_initializeation" do
9
+ config_file = Rails.root.join('config/balloon.yml')
10
+ if config_file.file?
11
+ config = YAML.load(ERB.new(config_file.read).result)
12
+ Balloon.configure_load(config, Rails.env)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ elsif defined?(Sinatra)
18
+ if defined?(Padrino) && defined?(PADRINO_ROOT)
19
+ root = PADRINO_ROOT
20
+ env = Padrino.env
21
+ else
22
+ root = Sinatra::Application.root
23
+ env = Sinatra::Application.environment
24
+ end
25
+ Balloon.root = root
26
+ config_file = File.join(root, 'config/balloon.yml')
27
+ if File.exist?(config_file)
28
+ config = YAML.load(ERB.new(File.read(config_file)).result)
29
+ Balloon.configure_load(config, env)
30
+ end
31
+ end
32
+
33
+ I18n.load_path << File.join(File.dirname(__FILE__), "locale", 'en.yml')
@@ -0,0 +1,7 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ response_error: "Http download errors"
5
+ connection_failed: "Http connection failed"
6
+ timeout_error: "Http connection time out"
7
+ down_mime_error: "Download file content type error"