boar 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +7 -0
- data/.travis-gemfile +13 -0
- data/.travis.yml +10 -0
- data/.yardopts +1 -0
- data/Gemfile +20 -0
- data/README.md +19 -0
- data/Rakefile +11 -0
- data/app/controllers/boar/application_controller.rb +16 -0
- data/app/controllers/boar/downloads_controller.rb +17 -0
- data/app/controllers/boar/pages_controller.rb +13 -0
- data/app/models/boar/handlers/authentication.rb +38 -0
- data/app/models/boar/handlers/downloads/base.rb +56 -0
- data/app/models/boar/handlers/downloads/box_net.rb +67 -0
- data/app/models/boar/handlers/downloads/dropbox.rb +59 -0
- data/app/models/boar/handlers/downloads/google_drive.rb +48 -0
- data/app/models/boar/handlers/downloads/local.rb +34 -0
- data/app/models/boar/handlers/downloads/remote.rb +24 -0
- data/app/models/boar/handlers/downloads/s3.rb +54 -0
- data/app/models/boar/handlers/downloads/sky_drive.rb +45 -0
- data/app/models/boar/handlers/generic.rb +25 -0
- data/app/models/boar/handlers/hosts.rb +28 -0
- data/app/models/boar/handlers/locale.rb +25 -0
- data/app/models/boar/handlers/path_mapper.rb +15 -0
- data/app/models/boar/handlers/root.rb +25 -0
- data/app/models/boar/handlers/views.rb +25 -0
- data/app/models/boar/services/downloads.rb +118 -0
- data/app/models/boar/services/generic.rb +78 -0
- data/app/models/boar/services/pages.rb +62 -0
- data/app/models/boar/utils/basic.rb +27 -0
- data/boar.gemspec +41 -0
- data/lib/boar.rb +31 -0
- data/lib/boar/configuration.rb +77 -0
- data/lib/boar/engine.rb +16 -0
- data/lib/boar/exceptions.rb +46 -0
- data/lib/boar/providers/base.rb +28 -0
- data/lib/boar/providers/box_net.rb +27 -0
- data/lib/boar/providers/dropbox.rb +26 -0
- data/lib/boar/providers/google_drive.rb +87 -0
- data/lib/boar/providers/sky_drive.rb +80 -0
- data/lib/boar/router.rb +68 -0
- data/lib/boar/version.rb +25 -0
- data/lib/tasks/boar.rake +102 -0
- data/spec/boar/controllers/application_controller_spec.rb +11 -0
- data/spec/boar/controllers/pages_controller_spec.rb +11 -0
- data/spec/boar/routes_spec.rb +11 -0
- data/spec/boar_spec.rb +7 -0
- data/spec/coverage_helper.rb +17 -0
- data/spec/spec_helper.rb +15 -0
- metadata +264 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
module Downloads
|
10
|
+
class Remote < Base
|
11
|
+
def call(path, entry, _, _, _)
|
12
|
+
# Get the url
|
13
|
+
url = entry[:url]
|
14
|
+
|
15
|
+
# We can't download a directory
|
16
|
+
raise Boar::Exceptions::NotFound.new(path) if url.blank?
|
17
|
+
|
18
|
+
# Redirect to the remote URL
|
19
|
+
@service.controller.redirect_to(self.interpolate(url, {path: path, entry: entry, options: @provider_options}))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
module Downloads
|
10
|
+
#noinspection RubyClassModuleNamingConvention
|
11
|
+
class S3 < Base
|
12
|
+
URL_AGE = 604800
|
13
|
+
|
14
|
+
def initialize(service, options)
|
15
|
+
super(service, options)
|
16
|
+
|
17
|
+
configuration = self.load_credentials
|
18
|
+
@s3_configuration = {access_key_id: configuration[:access_key], secret_access_key: configuration[:access_secret], region: configuration[:region]}
|
19
|
+
end
|
20
|
+
|
21
|
+
def call(path, entry, skip_cache, _, _)
|
22
|
+
# Read the URL from Redis
|
23
|
+
key = @configuration.backend_key("downloads:s3[#{path}]", self, @service.controller.request)
|
24
|
+
url = @configuration.backend.get(key)
|
25
|
+
|
26
|
+
if skip_cache || url.blank? then
|
27
|
+
begin
|
28
|
+
# Update the region
|
29
|
+
@s3_configuration[:region] = entry[:region] if entry[:region].present?
|
30
|
+
|
31
|
+
# Get the object
|
32
|
+
object = AWS::S3.new(@s3_configuration).buckets[entry[:bucket]].objects[entry[:key]]
|
33
|
+
raise ArgumentError if !object.exists?
|
34
|
+
|
35
|
+
# Get the public URL
|
36
|
+
url = object.url_for(:read, response_content_disposition: entry[:disposition], expire: Boar::Handlers::Downloads::S3::URL_AGE).to_s
|
37
|
+
|
38
|
+
# Save the URL
|
39
|
+
if url.present? then
|
40
|
+
@configuration.backend.set(key, url)
|
41
|
+
@configuration.backend.expire(key, Boar::Handlers::Downloads::S3::URL_AGE)
|
42
|
+
end
|
43
|
+
rescue => e
|
44
|
+
raise Boar::Exceptions::ServerError.new("[#{e.class}] #{e.message}")
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Redirect to the final URL
|
49
|
+
@service.controller.redirect_to(url)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
module Downloads
|
10
|
+
class SkyDrive < Base
|
11
|
+
def initialize(service, options)
|
12
|
+
super(service, options)
|
13
|
+
|
14
|
+
@client = Boar::Providers::SkyDrive.authorized_client(self.load_credentials, self.credentials_params)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(path, entry, skip_cache, _, _)
|
18
|
+
# Read the URL from Redis
|
19
|
+
key = @configuration.backend_key("downloads:sky_drive[#{path}]", self, @service.controller.request)
|
20
|
+
url = @configuration.backend.get(key)
|
21
|
+
|
22
|
+
if skip_cache || url.blank? then
|
23
|
+
begin
|
24
|
+
# Get the file
|
25
|
+
file = @client.get("/" + entry[:id]) rescue nil
|
26
|
+
raise Boar::Exceptions::NotFound if file.blank?
|
27
|
+
|
28
|
+
url = entry["disposition"] == "inline" ? file.link : file.download_link
|
29
|
+
raise Boar::Exceptions::NotFound if url.blank?
|
30
|
+
|
31
|
+
# Save the URL
|
32
|
+
@configuration.backend.set(key, url) if url.present?
|
33
|
+
rescue => e
|
34
|
+
raise e
|
35
|
+
raise Boar::Exceptions::ServerError.new("[#{e.class}] #{e.message}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Redirect to the final URL
|
40
|
+
@service.controller.redirect_to(url)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class Generic
|
10
|
+
include Boar::Utils::Basic
|
11
|
+
|
12
|
+
attr_accessor :service
|
13
|
+
attr_accessor :configuration
|
14
|
+
|
15
|
+
def initialize(service, _ = nil)
|
16
|
+
@service = service
|
17
|
+
@configuration = Rails.application.config.boar
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(*_)
|
21
|
+
raise Boar::Exceptions::UnImplemented.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class Hosts < Boar::Handlers::Generic
|
10
|
+
def initialize(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def call(request, domain = nil, port = nil)
|
14
|
+
domain ||= request.domain
|
15
|
+
port ||= request.port
|
16
|
+
rv = [domain, port].join(":")
|
17
|
+
|
18
|
+
if rv == "localhost:3000" then
|
19
|
+
rv = "localhost"
|
20
|
+
elsif ["http/80", "https/443"].include?([request.protocol, request.port].join("/")) then
|
21
|
+
rv = request.domain
|
22
|
+
end
|
23
|
+
|
24
|
+
rv
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class Locale < Boar::Handlers::Generic
|
10
|
+
attr_reader :locale_param
|
11
|
+
|
12
|
+
def initialize(service, options)
|
13
|
+
super(service)
|
14
|
+
|
15
|
+
# Get the parameter
|
16
|
+
@locale_param = self.get_option(options, :locale_param, @configuration.locale_param)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(*_)
|
20
|
+
# Retrieve locale from the controller's params.
|
21
|
+
@service.controller.params[@locale_param].ensure_string
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class PathMapper < Boar::Handlers::Generic
|
10
|
+
def call(_, path)
|
11
|
+
path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class Root < Boar::Handlers::Generic
|
10
|
+
attr_reader :template
|
11
|
+
|
12
|
+
def initialize(service, options)
|
13
|
+
super(service)
|
14
|
+
|
15
|
+
# Get the template for building the root
|
16
|
+
@template = self.get_option(options, :directory, @configuration.directory)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(*_)
|
20
|
+
# Interpolate to a directory
|
21
|
+
Pathname.new(self.interpolate(@template, {root: Rails.root, request: @service.controller.request, controller: @service.controller}))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Handlers
|
9
|
+
class Views < Boar::Handlers::Generic
|
10
|
+
attr_reader :views
|
11
|
+
|
12
|
+
def initialize(service, options)
|
13
|
+
super(service)
|
14
|
+
|
15
|
+
# Get the views
|
16
|
+
@views = self.get_option(options, :views, @configuration.views)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(*args)
|
20
|
+
# Interpolate the template
|
21
|
+
self.interpolate(@views.fetch(args[0]), ensure_hash(args[1]))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Services
|
9
|
+
class Downloads < Boar::Services::Generic
|
10
|
+
attr_accessor :downloads_configuration
|
11
|
+
|
12
|
+
def downloads
|
13
|
+
# Get the full path
|
14
|
+
path = @params[:path]
|
15
|
+
|
16
|
+
# Handle ACL for the path
|
17
|
+
self.handle_authentication(path, @options)
|
18
|
+
|
19
|
+
if !controller.performed? then
|
20
|
+
load_configuration(@skip_cache) # Instantiate the configuration
|
21
|
+
|
22
|
+
# Try to match the path against the list of files
|
23
|
+
match_data = nil
|
24
|
+
found = @downloads_configuration[:files].find{ |k, _| match_data = Regexp.new("^#{k}$").match(path) }
|
25
|
+
raise Boar::Exceptions::NotFound.new(path) if !found
|
26
|
+
|
27
|
+
# Get entry
|
28
|
+
regexp, entry = split_entry(found)
|
29
|
+
|
30
|
+
# Map the path
|
31
|
+
path = self.handler_for(:downloads_mapper, options).call(self, path)
|
32
|
+
|
33
|
+
# Now execute the provider. This will take care of acting on the controller
|
34
|
+
begin
|
35
|
+
provider_for_entry(entry).call(path, entry, @skip_cache, regexp, match_data)
|
36
|
+
rescue ::Mbrao::Exceptions::Unimplemented => e
|
37
|
+
raise Mbrao::Exceptions::Unimplemented.new(e)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def update
|
43
|
+
args = {nothing: true, status: :ok}
|
44
|
+
|
45
|
+
begin
|
46
|
+
load_configuration(true)
|
47
|
+
rescue => e
|
48
|
+
args = {text: e.message, status: 500}
|
49
|
+
end
|
50
|
+
|
51
|
+
@controller.render(args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def download_file(*args)
|
55
|
+
@controller.send_file(*args)
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def split_entry(found)
|
60
|
+
rv = found.last
|
61
|
+
rv = HashWithIndifferentAccess.new(rv.is_a?(Hash) ? rv : {provider: rv.ensure_string.to_sym}) # Make sure there is a provider key
|
62
|
+
|
63
|
+
# Get default provider is nothing is there
|
64
|
+
rv[:provider] ||= get_option(@options, :default_provider, @configuration.default_provider).to_s
|
65
|
+
|
66
|
+
[found.first, rv]
|
67
|
+
end
|
68
|
+
|
69
|
+
def provider_for_entry(entry)
|
70
|
+
# Instantiate the provider
|
71
|
+
@providers ||= {}
|
72
|
+
@providers[entry[:provider]] ||= ::Lazier.find_class(entry[:provider], "::Boar::Handlers::Downloads::%CLASS%", true).new(self, @downloads_configuration[:options])
|
73
|
+
end
|
74
|
+
|
75
|
+
def load_configuration(force = false)
|
76
|
+
# Setup stuff
|
77
|
+
config = Rails.application.config.boar
|
78
|
+
template = get_option(@options, :config, @configuration.config_file)
|
79
|
+
key = @configuration.backend_key("downloads", self, @controller.request)
|
80
|
+
|
81
|
+
# Delete from configuration
|
82
|
+
config.backend.del(key) if force
|
83
|
+
|
84
|
+
# Read the key
|
85
|
+
raw_downloads = config.backend.get(key)
|
86
|
+
raw_downloads = (ActiveSupport::JSON.decode(raw_downloads) rescue nil) if raw_downloads
|
87
|
+
|
88
|
+
@downloads_configuration = if raw_downloads then
|
89
|
+
HashWithIndifferentAccess.new(raw_downloads) # Just parse the read data
|
90
|
+
else
|
91
|
+
# Read the config file
|
92
|
+
downloads = YAML.load_file(self.interpolate(template, {root: Rails.root, request: @controller.request, controller: self}))
|
93
|
+
|
94
|
+
# Normalize
|
95
|
+
downloads = normalize_configuration(downloads)
|
96
|
+
|
97
|
+
# Save
|
98
|
+
config.backend.set(key, downloads.to_json)
|
99
|
+
|
100
|
+
downloads
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def normalize_configuration(configuration)
|
105
|
+
configuration = ensure_hash(configuration)
|
106
|
+
|
107
|
+
# Scope by host
|
108
|
+
configuration = ensure_hash(configuration[self.handler_for(:hosts).call(@controller.request)])
|
109
|
+
|
110
|
+
# Adjust some defaults
|
111
|
+
configuration[:files] = ensure_hash(configuration[:files])
|
112
|
+
configuration[:options] = ensure_hash(configuration[:options])
|
113
|
+
|
114
|
+
configuration
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
#
|
3
|
+
# This file is part of the boar gem. Copyright (C) 2013 and above Shogun <shogun_panda@me.com>.
|
4
|
+
# Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
|
5
|
+
#
|
6
|
+
|
7
|
+
module Boar
|
8
|
+
module Services
|
9
|
+
class Generic
|
10
|
+
attr_accessor :controller
|
11
|
+
attr_accessor :configuration
|
12
|
+
attr_accessor :options
|
13
|
+
attr_accessor :params
|
14
|
+
|
15
|
+
include Boar::Utils::Basic
|
16
|
+
|
17
|
+
def initialize(controller)
|
18
|
+
@controller = controller
|
19
|
+
@configuration = Rails.application.config.boar
|
20
|
+
@options = @controller.boar_options
|
21
|
+
@params = @controller.params
|
22
|
+
|
23
|
+
skip_cache_param = get_option(@options, :skip_cache_param, @configuration.skip_cache_param)
|
24
|
+
@skip_cache = skip_cache_param ? @controller.request.params[skip_cache_param].to_boolean : false
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(method)
|
28
|
+
begin
|
29
|
+
self.send(method)
|
30
|
+
rescue => e
|
31
|
+
e = Boar::Exceptions::UnImplemented.new if !self.respond_to?(method)
|
32
|
+
self.handle_error(e)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_error(exception)
|
37
|
+
if exception.is_a?(Lazier::Exceptions::Dump) then
|
38
|
+
raise exception
|
39
|
+
else
|
40
|
+
handler = self.handler_for(:views, @options)
|
41
|
+
|
42
|
+
# Get HTTP code
|
43
|
+
code = exception.is_a?(Boar::Exceptions::Error) ? exception.code : 500
|
44
|
+
|
45
|
+
# Basing on the code
|
46
|
+
view = case code
|
47
|
+
when 403 then handler.call(:error, code: 403)
|
48
|
+
when 404 then handler.call(:error, code: 404)
|
49
|
+
else
|
50
|
+
raise exception if !Boar::Exceptions::Error.must_raise?(exception)
|
51
|
+
handler.call(:error, code: 500, exception: exception)
|
52
|
+
end
|
53
|
+
|
54
|
+
@controller.render(file: view, status: code, formats: [:html]) if !@controller.performed?
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def handle_authentication(path, options = nil)
|
59
|
+
self.handler_for(:authentication, options).call(path)
|
60
|
+
end
|
61
|
+
|
62
|
+
def handler_for(scope, options = nil)
|
63
|
+
options = ensure_hash(options)
|
64
|
+
scope = scope.to_sym
|
65
|
+
|
66
|
+
# Get the handler specified by user
|
67
|
+
handlers_options = get_option(@options.merge(options), :handlers, {})
|
68
|
+
|
69
|
+
# Use either the user handler or the system one
|
70
|
+
handlers = @configuration.handlers.merge(handlers_options)
|
71
|
+
|
72
|
+
# Instantiate the handler
|
73
|
+
@boar_handlers ||= {}
|
74
|
+
@boar_handlers[scope] ||= ::Lazier.find_class(handlers[scope]).new(self, options)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|