bacchus 0.0.9 → 0.1.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.
data/lib/bacchus.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require "bacchus/version"
2
+ require "bacchus/access_pass"
3
+ require "bacchus/backend"
2
4
  require "bacchus/rack/beta_site"
@@ -0,0 +1,24 @@
1
+ module Bacchus
2
+ class AccessPass # TODO: AccessCode elsewhere (backend, see other places).
3
+ PARAM_KEY = "access_pass"
4
+ COOKIE_KEY = "access_pass"
5
+
6
+ def self.get(request)
7
+ AccessPass.new(request)
8
+ end
9
+
10
+ def initialize(request)
11
+ param = request.params[PARAM_KEY]
12
+ @pass = param || request.cookies[COOKIE_KEY] || ""
13
+ @updated = !param.nil? && !param.empty?
14
+ end
15
+
16
+ def maybe_save(response)
17
+ response.set_cookie(COOKIE_KEY, @pass) if @updated
18
+ end
19
+
20
+ def to_s
21
+ @pass
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,21 @@
1
+ require 'rest_client'
2
+
3
+ module Bacchus
4
+ class Backend
5
+ def initialize(base_url)
6
+ @base_url = base_url
7
+ end
8
+
9
+ def locked?(access_pass)
10
+ RestClient.get(path_to("/api/1/access/#{access_pass.to_s}")) do |response, _|
11
+ return response.code != 200
12
+ end
13
+ end
14
+
15
+ def path_to(resource)
16
+ File.join(@base_url, resource)
17
+ end
18
+ end
19
+ end
20
+
21
+
@@ -21,31 +21,48 @@ module Rack
21
21
  @excluded_routes = options[:except] || []
22
22
  @access_form_routes = options[:access_through] || []
23
23
  @access_template_route = options[:access_template] or raise "Specify the route to the template for the access form."
24
- @server = options[:server] or raise "Specify the address of the server."
24
+ base_url = options[:backend] or raise "Specify the address of the backend server."
25
+ @backend = Bacchus::Backend.new(base_url)
25
26
  end
26
27
 
27
28
  def call(env)
28
29
  request = Request.new(env)
29
- if access_form_route?(request)
30
- request.path = @access_template_route
31
- env["PATH_INFO"] = request.path
32
- env["REQUEST_URI"] = request.fullpath
33
- render_with_bacchus(env)
34
- elsif access_denied?(request)
35
- render_locked
36
- else
37
- @app.call(env)
38
- end
30
+ access_pass = Bacchus::AccessPass.get(request)
31
+ status, headers, body = respond_to(request, access_pass)
32
+ response = Response.new(body, status, headers)
33
+ access_pass.maybe_save(response)
34
+ response.finish
39
35
  end
40
36
 
41
37
  private
38
+
39
+ def respond_to(request, access_pass)
40
+ if @backend.locked?(access_pass)
41
+ if access_form_route?(request)
42
+ return render_with_bacchus(redirect(request, @access_template_route))
43
+ elsif access_denied?(request)
44
+ return render_locked
45
+ end
46
+ end
47
+
48
+ @app.call(request.env)
49
+ end
50
+
51
+ def redirect(original_request, path)
52
+ request = original_request.dup
53
+ request.path = @access_template_route
54
+ env = request.env
55
+ env["PATH_INFO"] = request.path
56
+ env["REQUEST_URI"] = request.fullpath
57
+ Request.new(env)
58
+ end
42
59
 
43
60
  def access_form_route?(request) # TODO: Duplication -- access_denied? & excluded_route?
44
61
  @access_form_routes.index {|route| matching_path?(request, route)}
45
62
  end
46
63
 
47
- def render_with_bacchus(env)
48
- status, headers, body = @app.call(env)
64
+ def render_with_bacchus(request)
65
+ status, headers, body = @app.call(request.env)
49
66
  script = <<-EOS
50
67
  <script src="#{path_to('bacchus.js')}" type="text/javascript"></script>
51
68
  EOS
@@ -57,7 +74,7 @@ module Rack
57
74
  ########################################################
58
75
 
59
76
  def path_to(file)
60
- ::File.join(@server, file)
77
+ @backend.path_to(file)
61
78
  end
62
79
 
63
80
  ########################################################
@@ -1,3 +1,3 @@
1
1
  module Bacchus
2
- VERSION = "0.0.9"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,54 @@
1
+ require_relative '../../lib/bacchus/access_pass'
2
+
3
+ module Bacchus
4
+ describe AccessPass do
5
+ let(:request) { mock("request") }
6
+ let(:access_pass) { "399tehu" }
7
+
8
+ before(:each) do
9
+ request.stub!(:params).and_return({})
10
+ request.stub!(:cookies).and_return({})
11
+ end
12
+
13
+ context "retrieving" do
14
+ it "should try to get it from request params" do
15
+ request.should_receive(:params).and_return({})
16
+ AccessPass.get(request)
17
+ end
18
+
19
+ it "should get it from params if present" do
20
+ request.stub!(:params).and_return("access_pass" => access_pass)
21
+ AccessPass.get(request).to_s.should == access_pass
22
+ end
23
+
24
+ it "should get it from cookies if not in params" do
25
+ request.stub!(:params).and_return({})
26
+ request.should_receive(:cookies).and_return("access_pass" => access_pass)
27
+ AccessPass.get(request).to_s.should == access_pass
28
+ end
29
+
30
+ it "should be empty if neither in params nor in cookies" do
31
+ request.stub!(:params).and_return({})
32
+ request.stub!(:cookies).and_return({})
33
+ AccessPass.get(request).to_s.should == ""
34
+ end
35
+ end
36
+
37
+ context "saving" do
38
+ let(:response) { mock("response") }
39
+
40
+ it "should save if updated from params" do
41
+ request.stub!(:params).and_return("access_pass" => access_pass)
42
+ response.should_receive(:set_cookie).with("access_pass", access_pass)
43
+ AccessPass.get(request).maybe_save(response)
44
+ end
45
+
46
+ it "should not save if not updated" do
47
+ request.stub!(:params).and_return({})
48
+ request.stub!(:cookies).and_return("access_pass" => access_pass)
49
+ response.should_not_receive(:set_cookie)
50
+ AccessPass.get(request).maybe_save(response)
51
+ end
52
+ end
53
+ end
54
+ end
@@ -1,47 +1,95 @@
1
1
  require 'rack/mock'
2
2
  require_relative '../../../lib/bacchus/rack/beta_site'
3
+ require_relative '../../../lib/bacchus/backend'
4
+ require_relative '../../../lib/bacchus/access_pass'
3
5
 
4
6
  describe Rack::BetaSite do
5
7
  let(:app) { lambda { |env| app_response } }
6
8
  let(:app_response) { [200, { 'Content-Type' => 'text/plain' }, ['<body>hello</body>']] }
7
9
  let(:access_template_route) { "/access_template" }
8
- let(:middleware) { Rack::BetaSite.new(app, except: ["/", %r{^/open/?$}], access_through: ["/form"], server: "localhost", access_template: access_template_route) }
10
+ let(:backend) { mock("backend").as_null_object }
11
+ let(:access_pass) { mock("access_pass").as_null_object }
12
+ let(:middleware) { Rack::BetaSite.new(app, except: ["/", %r{^/open/?$}], access_through: ["/form"], backend: "localhost", access_template: access_template_route) }
13
+
14
+ before(:each) do
15
+ Bacchus::Backend.stub!(:new).and_return(backend)
16
+ Bacchus::AccessPass.stub!(:get).and_return(access_pass)
17
+ end
9
18
 
10
19
  def response_for(sample_app, path)
11
20
  sample_app.call(Rack::MockRequest.env_for(path))
12
21
  end
13
22
 
23
+ it "should query the backend if the site is locked" do
24
+ request = mock("request").as_null_object
25
+ Rack::Request.stub!(:new).and_return(request)
26
+ Bacchus::AccessPass.should_receive(:get).with(request).and_return(access_pass)
27
+ backend.should_receive(:locked?).with(access_pass)
28
+ response_for(middleware, "/")
29
+ end
30
+
14
31
  context "given a locked site" do
32
+
33
+ before(:each) do
34
+ backend.stub!(:locked?).and_return(true)
35
+ end
36
+
15
37
  it "should block access to all pages" do
16
- sample_app = middleware
17
38
  status, * = response_for(middleware, "/page1")
18
39
  status.should == 500
19
40
  end
20
41
 
21
42
  it "should support string exceptions" do
22
- sample_app = middleware
23
43
  status, * = response_for(middleware, "/")
24
44
  status.should == 200
25
45
  end
26
46
 
27
47
  it "should support regex exceptions" do
28
- sample_app = middleware
29
48
  status, * = response_for(middleware, "/open")
30
49
  status.should == 200
31
50
  end
32
51
 
33
52
  it "should render access form script after the body closing tag" do
34
- sample_app = middleware
35
- status, _, body = response_for(middleware, "/form")
53
+ status, _, res = response_for(middleware, "/form")
36
54
  status.should == 200
37
- body.first.should include("hello")
38
- body.first.should include("</body>\n<script")
55
+ res.body.first.should include("hello")
56
+ res.body.first.should include("</body>\n<script")
39
57
  end
40
58
 
41
59
  it "should redirect to access template" do
42
- sample_app = middleware
43
60
  app.should_receive(:call).with(hash_including("PATH_INFO" => "/access_template")).and_return(app_response)
44
61
  response_for(middleware, "/form")
45
62
  end
46
63
  end
64
+
65
+ context "given an unlocked site" do
66
+ before(:each) do
67
+ backend.stub!(:locked?).and_return(false)
68
+ end
69
+
70
+ it "should allow access to all pages" do
71
+ status, * = response_for(middleware, "/page1")
72
+ status.should == 200
73
+ end
74
+
75
+ it "should not render access form script" do
76
+ status, _, res = response_for(middleware, "/form")
77
+ status.should == 200
78
+ res.body.first.should_not include("</body>\n<script")
79
+ end
80
+ end
81
+
82
+ context "should save access code" do
83
+ let(:response) { mock("response").as_null_object }
84
+ let(:access_pass) { mock("access_pass") }
85
+
86
+ before(:each) do
87
+ Rack::Response.stub!(:new).and_return(response)
88
+ end
89
+
90
+ it "should not set if not present" do
91
+ access_pass.should_receive(:maybe_save).with(response)
92
+ response_for(middleware, "/")
93
+ end
94
+ end
47
95
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bacchus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-11-03 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2012-11-06 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rest-client
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
14
30
  description: Adds support for private beta invites for Rack-based apps.
15
31
  email:
16
32
  - gyamtso@gmail.com
@@ -20,9 +36,12 @@ extra_rdoc_files: []
20
36
  files:
21
37
  - README.md
22
38
  - LICENSE.txt
39
+ - lib/bacchus/access_pass.rb
40
+ - lib/bacchus/backend.rb
23
41
  - lib/bacchus/rack/beta_site.rb
24
42
  - lib/bacchus/version.rb
25
43
  - lib/bacchus.rb
44
+ - spec/bacchus/access_pass_spec.rb
26
45
  - spec/bacchus/rack/beta_site_spec.rb
27
46
  homepage: ''
28
47
  licenses: []
@@ -49,4 +68,5 @@ signing_key:
49
68
  specification_version: 3
50
69
  summary: Beta invites for Rack-based apps.
51
70
  test_files:
71
+ - spec/bacchus/access_pass_spec.rb
52
72
  - spec/bacchus/rack/beta_site_spec.rb