boar 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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