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.
Files changed (50) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +7 -0
  3. data/.travis-gemfile +13 -0
  4. data/.travis.yml +10 -0
  5. data/.yardopts +1 -0
  6. data/Gemfile +20 -0
  7. data/README.md +19 -0
  8. data/Rakefile +11 -0
  9. data/app/controllers/boar/application_controller.rb +16 -0
  10. data/app/controllers/boar/downloads_controller.rb +17 -0
  11. data/app/controllers/boar/pages_controller.rb +13 -0
  12. data/app/models/boar/handlers/authentication.rb +38 -0
  13. data/app/models/boar/handlers/downloads/base.rb +56 -0
  14. data/app/models/boar/handlers/downloads/box_net.rb +67 -0
  15. data/app/models/boar/handlers/downloads/dropbox.rb +59 -0
  16. data/app/models/boar/handlers/downloads/google_drive.rb +48 -0
  17. data/app/models/boar/handlers/downloads/local.rb +34 -0
  18. data/app/models/boar/handlers/downloads/remote.rb +24 -0
  19. data/app/models/boar/handlers/downloads/s3.rb +54 -0
  20. data/app/models/boar/handlers/downloads/sky_drive.rb +45 -0
  21. data/app/models/boar/handlers/generic.rb +25 -0
  22. data/app/models/boar/handlers/hosts.rb +28 -0
  23. data/app/models/boar/handlers/locale.rb +25 -0
  24. data/app/models/boar/handlers/path_mapper.rb +15 -0
  25. data/app/models/boar/handlers/root.rb +25 -0
  26. data/app/models/boar/handlers/views.rb +25 -0
  27. data/app/models/boar/services/downloads.rb +118 -0
  28. data/app/models/boar/services/generic.rb +78 -0
  29. data/app/models/boar/services/pages.rb +62 -0
  30. data/app/models/boar/utils/basic.rb +27 -0
  31. data/boar.gemspec +41 -0
  32. data/lib/boar.rb +31 -0
  33. data/lib/boar/configuration.rb +77 -0
  34. data/lib/boar/engine.rb +16 -0
  35. data/lib/boar/exceptions.rb +46 -0
  36. data/lib/boar/providers/base.rb +28 -0
  37. data/lib/boar/providers/box_net.rb +27 -0
  38. data/lib/boar/providers/dropbox.rb +26 -0
  39. data/lib/boar/providers/google_drive.rb +87 -0
  40. data/lib/boar/providers/sky_drive.rb +80 -0
  41. data/lib/boar/router.rb +68 -0
  42. data/lib/boar/version.rb +25 -0
  43. data/lib/tasks/boar.rake +102 -0
  44. data/spec/boar/controllers/application_controller_spec.rb +11 -0
  45. data/spec/boar/controllers/pages_controller_spec.rb +11 -0
  46. data/spec/boar/routes_spec.rb +11 -0
  47. data/spec/boar_spec.rb +7 -0
  48. data/spec/coverage_helper.rb +17 -0
  49. data/spec/spec_helper.rb +15 -0
  50. 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