boar 1.0.1
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.
- 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
|