vanilla 1.9.11.1 → 1.9.12

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/Rakefile CHANGED
@@ -25,7 +25,7 @@ if Object.const_defined?(:Gem)
25
25
 
26
26
  # Change these as appropriate
27
27
  s.name = "vanilla"
28
- s.version = "1.9.11.1"
28
+ s.version = "1.9.12"
29
29
  s.summary = "A bliki-type web content thing."
30
30
  s.author = "James Adam"
31
31
  s.email = "james@lazyatom.com.com"
@@ -47,6 +47,7 @@ if Object.const_defined?(:Gem)
47
47
  s.add_dependency("RedCloth", ">= 4.1.1")
48
48
  s.add_dependency("BlueCloth", ">= 1.0.0")
49
49
  s.add_dependency("treetop", ">= 1.4.1")
50
+ s.add_dependency("warden", ">= 0.5.2")
50
51
 
51
52
  s.add_development_dependency("rspec") # add any other gems for testing/development
52
53
 
data/config.ru CHANGED
@@ -2,9 +2,19 @@ $:.unshift File.join(File.dirname(__FILE__), *%w[lib])
2
2
  require 'vanilla'
3
3
 
4
4
  app = Vanilla::App.new(ENV['VANILLA_CONFIG'])
5
+
5
6
  use Rack::Session::Cookie, :key => 'vanilla.session',
6
7
  :path => '/',
7
8
  :expire_after => 2592000,
8
9
  :secret => app.config[:secret]
10
+
11
+ require 'vanilla/authentication/warden'
12
+ app.authenticator = Vanilla::Authentication::Warden.new(app)
13
+ use Warden::Manager do |manager|
14
+ manager.default_strategies :vanilla
15
+ manager.failure_app = lambda{|e| [401, {"Content-Type" => "text/plain"}, ["Fail App"]]}
16
+ end
17
+
9
18
  use Rack::Static, :urls => ["/public"], :root => File.join(File.dirname(__FILE__))
10
- run app
19
+
20
+ run app
data/lib/vanilla/app.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  require 'vanilla/request'
2
+ require 'vanilla/authentication'
2
3
  require 'vanilla/routes'
3
4
  require 'vanilla/soup_with_timestamps'
4
5
 
@@ -11,16 +12,19 @@ require 'vanilla/renderers/erb'
11
12
  module Vanilla
12
13
  class App
13
14
  include Routes
14
-
15
+
15
16
  attr_reader :request, :response, :config, :soup
16
-
17
+ attr_accessor :authenticator
18
+
17
19
  def initialize(config_file=nil)
18
20
  prepare_configuration(config_file)
19
21
  @soup = SoupWithTimestamps.new(config[:soup])
22
+ @authenticator = Vanilla::Authentication::Base.new(self)
20
23
  end
21
-
24
+
22
25
  # Returns a Rack-appropriate 3-element array (via Rack::Response#finish)
23
26
  def call(env)
27
+ env['vanilla.app'] = self
24
28
  @request = Vanilla::Request.new(env, self)
25
29
  @response = Rack::Response.new
26
30
 
@@ -30,7 +34,7 @@ module Vanilla
30
34
  @response.status = 500
31
35
  output = e.to_s
32
36
  end
33
- response_format = request.format
37
+ response_format = request.format
34
38
  response_format = 'plain' if response_format == 'raw'
35
39
  @response['Content-Type'] = "text/#{response_format}"
36
40
  @response.write(output)
@@ -59,34 +63,34 @@ module Vanilla
59
63
  end
60
64
  end
61
65
 
62
- # Given the snip and parameters, yield an instance of the appropriate
66
+ # Given the snip and parameters, yield an instance of the appropriate
63
67
  # Vanilla::Render::Base subclass
64
68
  def rendering(snip)
65
69
  renderer_instance = renderer_for(snip).new(self)
66
70
  yield renderer_instance
67
71
  rescue Exception => e
68
- "<pre>[Error rendering '#{snip.name}' - \"" +
69
- e.message.gsub("<", "&lt;").gsub(">", "&gt;") + "\"]\n" +
72
+ "<pre>[Error rendering '#{snip.name}' - \"" +
73
+ e.message.gsub("<", "&lt;").gsub(">", "&gt;") + "\"]\n" +
70
74
  e.backtrace.join("\n").gsub("<", "&lt;").gsub(">", "&gt;") + "</pre>"
71
75
  end
72
-
76
+
73
77
  # Returns the renderer class for a given snip
74
78
  def renderer_for(snip)
75
79
  return Renderers::Base unless snip.render_as && !snip.render_as.empty?
76
80
  Vanilla::Renderers.const_get(snip.render_as)
77
81
  end
78
-
82
+
79
83
  # Other things can call this when a snip cannot be loaded.
80
84
  def render_missing_snip(snip_name)
81
85
  "[snip '#{snip_name}' cannot be found]"
82
86
  end
83
-
87
+
84
88
  def snip(attributes)
85
89
  @soup.new_snip(attributes)
86
90
  end
87
-
91
+
88
92
  private
89
-
93
+
90
94
  def prepare_configuration(config_file)
91
95
  config_file ||= "config.yml"
92
96
  @config = YAML.load(File.open(config_file)) rescue {}
@@ -0,0 +1,42 @@
1
+ require 'warden'
2
+
3
+ module Vanilla
4
+ module Authentication
5
+ class Warden < Base
6
+ def initialize(app)
7
+ super
8
+ ::Warden::Strategies.add(:vanilla, Vanilla::Authentication::Warden::Strategy)
9
+ end
10
+
11
+ def authenticated?
12
+ @app.request.env['warden'].authenticated?
13
+ end
14
+
15
+ def user
16
+ @app.request.env['warden'].user
17
+ end
18
+
19
+ def authenticate!
20
+ @app.request.env['warden'].authenticate!
21
+ end
22
+
23
+ def logout
24
+ @app.request.env['warden'].logout
25
+ end
26
+
27
+ class Strategy < ::Warden::Strategies::Base
28
+ def valid?
29
+ params["name"] || params["password"]
30
+ end
31
+
32
+ def authenticate!
33
+ if env['vanilla.app'].config[:credentials][params["name"]] == MD5.md5(params["password"]).to_s
34
+ success!(params["name"])
35
+ else
36
+ redirect!("/login")
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ module Vanilla
2
+ module Authentication
3
+ # A pass-through authenticator, which never
4
+ # requires a login
5
+ class Base
6
+ def initialize(app)
7
+ @app = app
8
+ end
9
+
10
+ def authenticated?
11
+ true
12
+ end
13
+
14
+ def user
15
+ end
16
+
17
+ def authenticate!
18
+ end
19
+
20
+ def logout
21
+ end
22
+ end
23
+ end
24
+ end
@@ -4,18 +4,18 @@ require 'vanilla/dynasnips/login'
4
4
  # The edit dyna will load the snip given in the 'snip_to_edit' part of the
5
5
  # params
6
6
  class EditSnip < Dynasnip
7
- include Login::Helper
8
-
9
7
  snip_name "edit"
10
-
8
+
11
9
  def get(snip_name=nil)
12
- return login_required unless logged_in?
10
+ app.request.authenticate!
11
+
13
12
  snip = app.soup[snip_name || app.request.params[:name]]
14
13
  edit(snip)
15
14
  end
16
-
15
+
17
16
  def post(*args)
18
- return login_required unless logged_in?
17
+ app.request.authenticate!
18
+
19
19
  snip_attributes = cleaned_params
20
20
  snip_attributes.delete(:save_button)
21
21
  return 'no params' if snip_attributes.empty?
@@ -29,20 +29,20 @@ class EditSnip < Dynasnip
29
29
  app.soup << snip_attributes
30
30
  %{Created snip #{link_to snip_attributes[:name]} ok}
31
31
  end
32
-
32
+
33
33
  def edit(snip)
34
34
  renderer = Vanilla::Renderers::Erb.new(app)
35
35
  renderer.instance_eval { @snip_to_edit = snip } # hacky!
36
36
  snip_in_edit_template = renderer.render_without_including_snips(app.soup['edit'], :template)
37
37
  prevent_snip_inclusion(snip_in_edit_template)
38
38
  end
39
-
39
+
40
40
  private
41
-
41
+
42
42
  def prevent_snip_inclusion(content)
43
43
  content.gsub("{", "&#123;").gsub("}" ,"&#125;")
44
44
  end
45
-
45
+
46
46
  attribute :template, %{
47
47
  <form action="<%= url_to 'edit' %>" method="post">
48
48
  <dl class="attributes">
@@ -57,4 +57,4 @@ class EditSnip < Dynasnip
57
57
  <button name='save_button'>Save</button>
58
58
  </form>
59
59
  }
60
- end
60
+ end
@@ -3,43 +3,27 @@ require 'yaml'
3
3
  require 'md5'
4
4
 
5
5
  class Login < Dynasnip
6
- module Helper
7
- def logged_in?
8
- !current_user.nil?
9
- end
10
-
11
- def current_user
12
- app.request.session['logged_in_as']
13
- end
14
-
15
- def login_required
16
- "You need to <a href='/login'>login</a> to do that."
17
- end
18
- end
19
- include Helper
20
-
21
6
  def get(*args)
22
- if logged_in?
7
+ if app.request.authenticated?
23
8
  login_controls
24
9
  else
25
10
  render(self, 'template')
26
11
  end
27
12
  end
28
-
13
+
29
14
  def post(*args)
30
- if app.config[:credentials][cleaned_params[:name]] == MD5.md5(cleaned_params[:password]).to_s
31
- app.request.session['logged_in_as'] = cleaned_params[:name]
15
+ if app.request.authenticate!
32
16
  login_controls
33
17
  else
34
18
  "login fail!"
35
19
  end
36
20
  end
37
-
21
+
38
22
  def delete(*args)
39
- app.request.session['logged_in_as'] = nil
23
+ app.request.logout
40
24
  "Logged out"
41
25
  end
42
-
26
+
43
27
  attribute :template, <<-EHTML
44
28
  <form action='/login' method='post'>
45
29
  <label>Name: <input type="text" name="name"></input></label>
@@ -47,10 +31,10 @@ class Login < Dynasnip
47
31
  <button>login</button>
48
32
  </form>
49
33
  EHTML
50
-
34
+
51
35
  private
52
-
36
+
53
37
  def login_controls
54
- "logged in as {link_to #{app.request.session['logged_in_as']}}; <a href='/login?_method=delete'>logout</a>"
38
+ "logged in as #{link_to app.request.user}; <a href='/login?_method=delete'>logout</a>"
55
39
  end
56
40
  end
@@ -2,13 +2,14 @@ require 'vanilla/dynasnip'
2
2
  require 'vanilla/dynasnips/login'
3
3
 
4
4
  class NewSnip < Dynasnip
5
- include Login::Helper
6
-
5
+ # include Login::Helper
6
+
7
7
  snip_name :new
8
-
8
+
9
9
  def handle(*arg)
10
- return login_required unless logged_in?
10
+ app.request.authenticate!
11
+
11
12
  base_params = {:render_as => '', :content => '', :author => current_user}.update(app.request.params)
12
13
  editor = EditSnip.new(app).edit(Snip.new(base_params))
13
14
  end
14
- end
15
+ end
@@ -4,9 +4,10 @@ module Vanilla
4
4
  # Create a request with symbolised access to the params, and some special
5
5
  # accessors to the snip, part and format based on our routing.
6
6
  class Request
7
- attr_reader :snip_name, :part, :format, :method
8
-
7
+ attr_reader :snip_name, :part, :format, :method, :env
8
+
9
9
  def initialize(env, app)
10
+ @env = env
10
11
  @rack_request = Rack::Request.new(env)
11
12
  @app = app
12
13
  determine_request_uri_parts
@@ -16,41 +17,57 @@ module Vanilla
16
17
  # Don't you just love how terse functional programming tends to look like maths?
17
18
  @symbolised_params ||= @rack_request.params.inject({}) { |p, (k,v)| p[k.to_sym] = v; p }
18
19
  end
19
-
20
+
20
21
  # Returns the snip referenced by the request's URL. Performs no exception
21
22
  # handling, so if the snip does not exist, an exception will be thrown.
22
23
  def snip
23
24
  @app.soup[snip_name]
24
25
  end
25
-
26
+
26
27
  def cookies
27
28
  @rack_request.cookies
28
29
  end
29
-
30
+
30
31
  def ip
31
32
  @rack_request.env["REMOTE_ADDR"]
32
33
  end
33
-
34
+
34
35
  def session
35
36
  @rack_request.env["rack.session"]
36
37
  end
37
-
38
+
39
+ def authenticated?
40
+ @app.authenticator.authenticated?
41
+ end
42
+
43
+ def user
44
+ @app.authenticator.user
45
+ end
46
+
47
+ def authenticate!
48
+ @app.authenticator.authenticate!
49
+ end
50
+
51
+ def logout
52
+ @app.authenticator.logout
53
+ end
54
+
38
55
  private
39
-
56
+
40
57
  def determine_request_uri_parts
41
58
  @snip_name, @part, @format = request_uri_parts(@rack_request)
42
59
  @format ||= 'html'
43
60
  @method = (params.delete(:_method) || @rack_request.request_method).downcase
44
61
  end
45
-
62
+
46
63
  def uri_path(request)
47
64
  request.path_info
48
65
  end
49
-
66
+
50
67
  URL_ROOT = /\A\/\Z/ # i.e. /
51
68
  URL_SNIP = /\A\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /start, /start.html
52
69
  URL_SNIP_AND_PART = /\A\/([\w\-\s]+)\/([\w\-\s]+)(\/|\.(\w+))?\Z/ # i.e. /blah/part, /blah/part.raw
53
-
70
+
54
71
  # Returns an array of the requested snip, part and format
55
72
  def request_uri_parts(request)
56
73
  case CGI.unescape(uri_path(request))
@@ -64,6 +81,6 @@ module Vanilla
64
81
  []
65
82
  end
66
83
  end
67
-
84
+
68
85
  end
69
- end
86
+ end
@@ -9,6 +9,7 @@ system.main_template = <<-HTML
9
9
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
10
10
  <title>{current_snip name}</title>
11
11
  <script language="javascript" src="/public/javascripts/jquery.js"></script>
12
+ <script language="javascript" src="/public/javascripts/jquery.autogrow-textarea.js"></script>
12
13
  <script language="javascript" src="/public/javascripts/vanilla.js"></script>
13
14
  <link rel="stylesheet" type="text/css" media="screen" href="<%= url_to("system", "css.css") %>" />
14
15
  </head>
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vanilla
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.11.1
4
+ version: 1.9.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Adam
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-10-16 00:00:00 +01:00
12
+ date: 2009-11-10 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -72,6 +72,16 @@ dependencies:
72
72
  - !ruby/object:Gem::Version
73
73
  version: 1.4.1
74
74
  version:
75
+ - !ruby/object:Gem::Dependency
76
+ name: warden
77
+ type: :runtime
78
+ version_requirement:
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: 0.5.2
84
+ version:
75
85
  - !ruby/object:Gem::Dependency
76
86
  name: rspec
77
87
  type: :development
@@ -113,6 +123,8 @@ files:
113
123
  - lib/defensio.rb
114
124
  - lib/tasks/vanilla.rake
115
125
  - lib/vanilla/app.rb
126
+ - lib/vanilla/authentication/warden.rb
127
+ - lib/vanilla/authentication.rb
116
128
  - lib/vanilla/console.rb
117
129
  - lib/vanilla/dynasnip.rb
118
130
  - lib/vanilla/dynasnips/comments.rb