balloon 1.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.
@@ -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"