equipment 0.1.0 → 1.4.84
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +9 -0
- data/LICENSE +340 -0
- data/README +29 -12
- data/Rakefile +157 -0
- data/TODO +14 -0
- data/doc/structure.dia +0 -0
- data/doc/structure.png +0 -0
- data/lib/camping_ext.rb +72 -0
- data/lib/equipment.rb +39 -116
- data/lib/ext.rb +33 -0
- data/lib/ext/active_record.rb +146 -0
- data/lib/ext/basic_auth.rb +15 -15
- data/lib/ext/controls.rb +16 -14
- data/lib/ext/flash.rb +35 -17
- data/lib/ext/form_helpers.rb +46 -0
- data/lib/ext/forward.rb +44 -15
- data/lib/ext/js_helpers.rb +66 -19
- data/lib/ext/logging.rb +61 -0
- data/lib/ext/mount.rb +33 -27
- data/lib/ext/negociate_content.rb +90 -0
- data/lib/ext/og.rb +18 -10
- data/lib/ext/og_scaffold.rb +5 -8
- data/lib/ext/resource.rb +127 -0
- data/lib/ext/security.rb +66 -31
- data/lib/ext/sendfile.rb +3 -4
- data/lib/ext/settings.rb +243 -0
- data/lib/ext/template_view.rb +9 -37
- data/lib/ext/use_helper.rb +6 -10
- data/lib/ext/view.rb +98 -0
- data/lib/ext/view_slot.rb +60 -0
- data/lib/mimetype_ext.rb +12 -0
- data/lib/more/typecast.rb +288 -0
- data/lib/ruby_ext.rb +126 -0
- data/share/js/date_ext.js +234 -0
- data/share/js/es-confirm.js +23 -0
- data/share/js/event-selector.js +145 -0
- data/share/js/jquery.js +1793 -0
- data/share/js/prototype.js +2012 -0
- metadata +50 -35
- data/ProjectInfo +0 -55
- data/examples/basicauthtest.rb +0 -59
- data/examples/erubytest.rb +0 -36
- data/examples/flashtest.rb +0 -46
- data/examples/index.erb +0 -9
- data/examples/mounttest.rb +0 -34
- data/examples/ogtest.rb +0 -41
- data/examples/patchestest.rb +0 -40
- data/examples/sendfiletest.rb +0 -29
- data/lib/ext/forms.rb +0 -22
- data/lib/ext/patches.rb +0 -130
- data/lib/ext/ressource.rb +0 -88
data/lib/ext/security.rb
CHANGED
@@ -1,79 +1,114 @@
|
|
1
1
|
require 'equipment'
|
2
|
-
require 'ext/
|
2
|
+
require 'ext/app_util'
|
3
3
|
require 'ext/forward'
|
4
|
+
require 'ext/view'
|
4
5
|
|
5
6
|
module Ext
|
6
7
|
|
7
|
-
# Generic authentication module. Used by BasicAuth for example.
|
8
|
+
# Generic authentication module. Used by BasicAuth for example.
|
9
|
+
#
|
10
|
+
# == Warning
|
11
|
+
#
|
12
|
+
# Never use this module alone. You should at least create another module that
|
13
|
+
# extends Base. This is because of how Equipment works right now. You wouldn't
|
14
|
+
# be able to define authenticate and authorize and call super. Ask zimbatm for
|
15
|
+
# more information on this if you're interested... :-)
|
16
|
+
#
|
17
|
+
# == Usage
|
18
|
+
#
|
19
|
+
# Security is split in two methods ; authenticate and authorize.
|
20
|
+
# The role of authenticate is to detect the user, loaded by session or
|
21
|
+
# other. The role of authorize is to tell if the user is authorized or
|
22
|
+
# not. Authorize must be overriden if you want to secure some place of
|
23
|
+
# your app. Defining it in Base will act globally. You can also define
|
24
|
+
# them individually in each controller, like you want. Finally, both
|
25
|
+
# methods are chained, so you can use super to mix various security
|
26
|
+
# mechanism.
|
27
|
+
#
|
28
|
+
# In your app, override authenticate if you want to load your users
|
29
|
+
# from the database. eg.
|
30
|
+
#
|
31
|
+
# def authenticate
|
32
|
+
# user, pass = *super
|
33
|
+
# @user = User.find_by_login_and_password(user, pass)
|
34
|
+
# return [user, pass] if @user
|
35
|
+
# return [nil, nil]
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Override authotize like that
|
39
|
+
#
|
40
|
+
# def authorize(user, pass)
|
41
|
+
# # some auth mechanism
|
42
|
+
# if user == pass
|
43
|
+
# return true
|
44
|
+
# else
|
45
|
+
# return false
|
46
|
+
# end
|
47
|
+
# end
|
8
48
|
#
|
9
49
|
# == Dependencies
|
10
50
|
#
|
11
51
|
# * Equipment
|
52
|
+
# * AppUtil
|
12
53
|
# * Forward
|
13
|
-
# *
|
14
|
-
#
|
15
|
-
# == TODO
|
54
|
+
# * View
|
16
55
|
#
|
17
|
-
# * More doc
|
18
56
|
module Security
|
19
57
|
extend Equipment
|
20
|
-
depends_on
|
58
|
+
depends_on AppUtil
|
21
59
|
depends_on Forward
|
22
|
-
|
23
|
-
def self.equip(app)
|
24
|
-
super
|
25
|
-
app::Controllers::Unauthorized.send :include, app::C, app::Base, app::Models
|
26
|
-
app::Controllers::Unauthenticated.send :include, app::C, app::Base, app::Models
|
27
|
-
end
|
60
|
+
depends_on View
|
28
61
|
|
29
62
|
module Base
|
30
|
-
# Blank authentication, returns [nil, nil]
|
63
|
+
# Blank authentication terminator, returns [nil, nil]
|
31
64
|
def authenticate; return nil, nil end
|
32
65
|
|
33
|
-
# Blank authorization, returns
|
34
|
-
def authorize(user, pass
|
66
|
+
# Blank authorization terminator, returns nil as ternary operator.
|
67
|
+
def authorize(user, pass); return nil end
|
35
68
|
|
36
69
|
# Checks the credencials when serving a page if `authorize` is defined
|
37
|
-
# in your app, Base or controller.
|
70
|
+
# in your app, Base or controller. If you forward to controllers
|
71
|
+
# that don't have urls, the security will not be checked.
|
38
72
|
def service(*a)
|
39
|
-
|
73
|
+
return super if self.class.urls.empty?
|
40
74
|
user, pass = authenticate
|
41
|
-
if authorize(user, pass)
|
42
|
-
super
|
75
|
+
if authorize(user, pass) != false # nil is accepted, not false
|
76
|
+
return super
|
43
77
|
elsif not user
|
44
|
-
|
45
|
-
forward(app::Controllers::Unauthenticated)
|
78
|
+
forward app::Controllers::Unauthenticated, 'get'
|
46
79
|
else
|
47
|
-
|
48
|
-
forward(app::Controllers::Unauthorized, user)
|
80
|
+
forward app::Controllers::Unauthorized, 'get', user
|
49
81
|
end
|
50
82
|
self
|
51
83
|
end
|
52
84
|
|
53
85
|
end
|
54
86
|
|
87
|
+
# Security defines two controllers that correspond to your those two
|
88
|
+
# methods.
|
55
89
|
module Controllers
|
56
90
|
# Called when an url is not authorized. You can override this is your app.
|
57
91
|
# Or create an `unauthorized` view. @bad_user is the user name.
|
58
92
|
class Unauthorized
|
59
93
|
def self.urls; [] end # do not serve urls directly.
|
60
|
-
def authenticate; return nil, nil end
|
61
|
-
def authorize(user, pass, force=false); true; end
|
62
94
|
|
63
95
|
def get(bad_user)
|
64
96
|
@bad_user = bad_user
|
65
|
-
|
97
|
+
if has_view?(:unauthorized)
|
98
|
+
render(:unauthorized)
|
99
|
+
else "Unauthorized user : #@bad_user" end
|
66
100
|
end
|
67
101
|
end
|
68
102
|
|
69
|
-
# Customize by creating an "unauthenticated" view
|
103
|
+
# Customize by creating an "unauthenticated" view. You could
|
104
|
+
# implement a login page here.
|
70
105
|
class Unauthenticated
|
71
106
|
def self.urls; [] end # do not serve urls directly.
|
72
|
-
def authenticate; return nil, nil end
|
73
|
-
def authorize(user, pass, force=false); true; end
|
74
107
|
|
75
108
|
def get
|
76
|
-
|
109
|
+
if has_view?(:unauthenticated)
|
110
|
+
render(:unauthenticated)
|
111
|
+
else 'Unauthenticated' end
|
77
112
|
end
|
78
113
|
end
|
79
114
|
|
data/lib/ext/sendfile.rb
CHANGED
@@ -3,7 +3,7 @@ require 'ext/app_util'
|
|
3
3
|
require 'ext/forward'
|
4
4
|
|
5
5
|
begin
|
6
|
-
require '
|
6
|
+
require 'mimetype_ext' # requires that package
|
7
7
|
rescue LoadError
|
8
8
|
STDERR.puts '*** mime/types not available. You will have to specify mime \
|
9
9
|
types in Equipment::Sendfile.'
|
@@ -23,7 +23,6 @@ module Ext
|
|
23
23
|
# == Dependencies
|
24
24
|
#
|
25
25
|
# * Equipment
|
26
|
-
# * AppUtil
|
27
26
|
# * Forward
|
28
27
|
# * `mime-types` package. Available as a gem.
|
29
28
|
# * `sendfile` package (optional). Available as a gem.
|
@@ -68,13 +67,13 @@ module Ext
|
|
68
67
|
|
69
68
|
# Sendfile is used ?
|
70
69
|
if $mongrel_has_sendfile
|
71
|
-
@headers['X-
|
70
|
+
@headers['X-SENDFILE'] = path
|
72
71
|
else
|
73
72
|
@body = file.read
|
74
73
|
end
|
75
74
|
|
76
75
|
rescue Errno::ENOENT, Errno::EISDIR # File not found
|
77
|
-
forward
|
76
|
+
forward app::Controllers::NotFound, 'get', @env.PATH_INFO
|
78
77
|
ensure
|
79
78
|
file.close if file
|
80
79
|
end
|
data/lib/ext/settings.rb
ADDED
@@ -0,0 +1,243 @@
|
|
1
|
+
require 'equipment'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module Ext
|
6
|
+
# Settings allow you to have configurable settings in your app. Define
|
7
|
+
# your own configuration settings in the app root and then call
|
8
|
+
# #load_settings.
|
9
|
+
#
|
10
|
+
# NOTE : This Equipment is usable without Camping.
|
11
|
+
#
|
12
|
+
# == Example
|
13
|
+
#
|
14
|
+
# require 'camping'
|
15
|
+
# require 'ext/settings'
|
16
|
+
#
|
17
|
+
# Camping.goes :YourApp
|
18
|
+
#
|
19
|
+
# module YourApp
|
20
|
+
# equip Ext::Settings
|
21
|
+
#
|
22
|
+
# setting :database, {:store=>'mysql', :hostname=>'localhost'}
|
23
|
+
#
|
24
|
+
# load_settings('your_config.yaml')
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# YourApp.database #=> {:store=>'mysql', :hostname=>'localhost'}
|
28
|
+
#
|
29
|
+
# == Dependencies
|
30
|
+
#
|
31
|
+
# * Equipment
|
32
|
+
# * YAML
|
33
|
+
# * Forwardable
|
34
|
+
#
|
35
|
+
# == TODO
|
36
|
+
#
|
37
|
+
# Implement type-casting ?
|
38
|
+
#
|
39
|
+
module Settings
|
40
|
+
extend Equipment
|
41
|
+
|
42
|
+
# Define C if not defined.
|
43
|
+
def self.equip(app)
|
44
|
+
app.module_eval "C=self" unless app.const_defined? :C
|
45
|
+
super
|
46
|
+
end
|
47
|
+
|
48
|
+
# Class methods for your app.
|
49
|
+
module CClassMethods
|
50
|
+
attr_accessor :settings_path
|
51
|
+
|
52
|
+
# This is the method that let you create settings. If you pass a
|
53
|
+
# block, it will be called when the key is assigned and the return
|
54
|
+
# value will be used.
|
55
|
+
#
|
56
|
+
# == Example
|
57
|
+
#
|
58
|
+
# setting :user, 'HEY', do |new,old|
|
59
|
+
# new.downcase
|
60
|
+
# end
|
61
|
+
#
|
62
|
+
# self.user #=> "hey"
|
63
|
+
def setting(key, value, &on_change)
|
64
|
+
settings.set(key, value, &on_change)
|
65
|
+
|
66
|
+
# reader
|
67
|
+
metaclass.send :define_method, key do
|
68
|
+
settings[key].value
|
69
|
+
end
|
70
|
+
|
71
|
+
# writer
|
72
|
+
metaclass.send :define_method, "#{key}=" do |val|
|
73
|
+
settings[key].value = val
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# The group of settings. You can call settings.to_yaml to get the
|
78
|
+
# output.
|
79
|
+
def settings; @settings ||= SettingGroup.new(self) end
|
80
|
+
|
81
|
+
# Loads the specified file. If none is given, it will look in /etc
|
82
|
+
# and your home folder for a file called you_app.yaml
|
83
|
+
def load_settings(yaml_file=settings_path)
|
84
|
+
if yaml_file
|
85
|
+
settings.load(yaml_file)
|
86
|
+
puts "INFO: '#{yaml_file}' loaded." if $DBG
|
87
|
+
else
|
88
|
+
name = self.name.methodize
|
89
|
+
|
90
|
+
# YAML config
|
91
|
+
configs = []
|
92
|
+
configs << File.join(ENV['HOME'], ".#{name}.yaml") if ENV['HOME']
|
93
|
+
configs << File.join(ENV['APPDATA'], "#{name}.yaml") if ENV['APPDATA']
|
94
|
+
configs << "/etc/#{name}.yaml"
|
95
|
+
configs.each do |conf|
|
96
|
+
conf = File.expand_path(conf)
|
97
|
+
if File.exists?(conf)
|
98
|
+
settings_path = conf
|
99
|
+
load_settings(conf)
|
100
|
+
break
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Ruby config
|
105
|
+
configs = []
|
106
|
+
configs << File.join(ENV['HOME'], ".#{name}.rb") if ENV['HOME']
|
107
|
+
configs << File.join(ENV['APPDATA'], "#{name}.yaml") if ENV['APPDATA']
|
108
|
+
configs << "/etc/#{name}.rb"
|
109
|
+
configs.each do |conf|
|
110
|
+
conf = File.expand_path(conf)
|
111
|
+
if File.exists?(conf)
|
112
|
+
load conf
|
113
|
+
break
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# Export the settings once they're changed. You'll have to call
|
120
|
+
# this by hand.
|
121
|
+
#
|
122
|
+
# Oh and, the keys will be stored in the following format :
|
123
|
+
# 'YourApp.keyname'
|
124
|
+
def save_settings(yaml_file=settings_path)
|
125
|
+
raise ArgumentError, "No settings path given" unless yaml_file
|
126
|
+
settings.save(yaml_file)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# This is the class that represent one setting. You should not use
|
131
|
+
# that directly but access it trough the YourApp.settings method.
|
132
|
+
#
|
133
|
+
# default_value is the value that you specified when defining the
|
134
|
+
# setting.
|
135
|
+
class Setting
|
136
|
+
# klass is not used here. It's for YAML.
|
137
|
+
attr_reader :klass, :key, :value, :default_value
|
138
|
+
def initialize(klass, key, default_value, &on_change)
|
139
|
+
@klass, @key = klass, key
|
140
|
+
@on_change = on_change
|
141
|
+
@default_value = self.value = default_value
|
142
|
+
end
|
143
|
+
|
144
|
+
# Calls the on_change transformer if available.
|
145
|
+
def value=(new_val)
|
146
|
+
if @on_change
|
147
|
+
@value = @on_change.call(new_val)
|
148
|
+
else
|
149
|
+
@value = new_val
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def on_change(&block)
|
154
|
+
raise ArgumentError, "please give a block" unless block_given?
|
155
|
+
@on_change = block
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# This is the class that represent YourApp.settings. Do not use it
|
160
|
+
# directly. Kind of HashWithIndifferentAccess.
|
161
|
+
class SettingGroup
|
162
|
+
extend Forwardable
|
163
|
+
|
164
|
+
def_delegators :@hash, :keys
|
165
|
+
|
166
|
+
# To generate the YAML keys.
|
167
|
+
attr_reader :klass
|
168
|
+
|
169
|
+
def initialize(klass)
|
170
|
+
@klass = klass
|
171
|
+
@hash = {}
|
172
|
+
end
|
173
|
+
|
174
|
+
def get(key)
|
175
|
+
key = convert_key(key)
|
176
|
+
@hash[key]
|
177
|
+
end
|
178
|
+
alias_method :[], :get
|
179
|
+
|
180
|
+
def set(key, value, &on_change)
|
181
|
+
key = convert_key(key)
|
182
|
+
raise ArgumentError, "#{klass}.#{key} already defined" if @hash.has_key? key
|
183
|
+
@hash[key] = Setting.new(klass, key, value, &on_change)
|
184
|
+
end
|
185
|
+
alias_method :[]=, :set
|
186
|
+
|
187
|
+
def method_missing(m)
|
188
|
+
raise NoMethodError unless @hash.has_key? m
|
189
|
+
@hash[m]
|
190
|
+
end
|
191
|
+
|
192
|
+
# Loads your configuration file. Used by load_settings.
|
193
|
+
def load(file)
|
194
|
+
|
195
|
+
case file
|
196
|
+
when String
|
197
|
+
file = File.open(file)
|
198
|
+
end
|
199
|
+
|
200
|
+
vals = YAML::load(file)
|
201
|
+
if vals.kind_of? Hash
|
202
|
+
vals.select{|k,v| /^#{klass.name}\./ =~ k}.each do |k,v|
|
203
|
+
key = k.sub /^#{klass.name}\./,''
|
204
|
+
if @hash.has_key? key
|
205
|
+
@hash[key].value = v
|
206
|
+
else
|
207
|
+
puts "INFO: #{klass.name}.#{key} does not exist. #{@hash.inspect}"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Exports your configuration file as YAML. Used by save_settings.
|
214
|
+
def save(file)
|
215
|
+
|
216
|
+
case file
|
217
|
+
when String
|
218
|
+
file = File.open(file, 'w')
|
219
|
+
end
|
220
|
+
|
221
|
+
file.write(to_yaml)
|
222
|
+
end
|
223
|
+
|
224
|
+
def to_hash
|
225
|
+
@hash.keys.sort.inject(Hash.new) do |hash,k|
|
226
|
+
hash["#{klass}.#{k}"] = @hash[k].value
|
227
|
+
hash
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def to_yaml
|
232
|
+
to_hash.to_yaml
|
233
|
+
end
|
234
|
+
|
235
|
+
private
|
236
|
+
|
237
|
+
def convert_key(key)
|
238
|
+
key.to_s
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
data/lib/ext/template_view.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
require 'equipment'
|
2
|
-
require 'ext/
|
2
|
+
require 'ext/view'
|
3
|
+
|
4
|
+
raise "Templates are broken for now, sorry !"
|
3
5
|
|
4
6
|
module Ext
|
5
|
-
# A microcospical extension to decouple views from camping.
|
6
|
-
# the ones based on templates.
|
7
|
+
# A microcospical extension to decouple template views from camping.
|
7
8
|
#
|
8
9
|
# Adds a V class to your app on which all instance variables
|
9
10
|
# will be sent before rendering the view.
|
@@ -11,39 +12,26 @@ module Ext
|
|
11
12
|
# == Dependencies
|
12
13
|
#
|
13
14
|
# * Equipment
|
14
|
-
# *
|
15
|
+
# * View
|
15
16
|
#
|
16
17
|
# == TODO
|
17
18
|
#
|
18
19
|
# * Add support for layouts
|
19
20
|
module TemplateView
|
20
21
|
extend Equipment
|
21
|
-
depends_on
|
22
|
-
|
23
|
-
def self.equip(app)
|
24
|
-
super
|
25
|
-
app.module_eval <<-SOME_VIEW
|
26
|
-
# Some kind of view data proxy for template-based renderers
|
27
|
-
class V
|
28
|
-
include Helpers
|
29
|
-
include Controllers
|
30
|
-
def bind(m,*a,&b); binding; end
|
31
|
-
def R(klass, *args); self / super; end
|
32
|
-
end
|
33
|
-
SOME_VIEW
|
34
|
-
end
|
22
|
+
depends_on View
|
35
23
|
|
36
24
|
module Base
|
37
25
|
# Takes template_root from ViewsClassMethods#template_root.
|
38
26
|
#
|
39
27
|
# You can change that by setting @template_root in your controller.
|
40
|
-
def template_root; @template_root || app
|
28
|
+
def template_root; @template_root || app.template_root || '' end
|
41
29
|
|
42
30
|
# Same as #template_root
|
43
|
-
def use_cache; @use_cache || app
|
31
|
+
def use_cache; @use_cache || app.use_cache; end
|
44
32
|
end
|
45
33
|
|
46
|
-
module
|
34
|
+
module CClassMethods
|
47
35
|
# Sets the template_root. Usage is up to the template.
|
48
36
|
attr_accessor :template_root
|
49
37
|
|
@@ -54,19 +42,3 @@ module Ext
|
|
54
42
|
|
55
43
|
end
|
56
44
|
|
57
|
-
class Object
|
58
|
-
|
59
|
-
# Sets all instance variables of an object to another
|
60
|
-
#
|
61
|
-
# if force is set to true, existing instance variables will be overwritten
|
62
|
-
def instance_variables_send(obj, force=false)
|
63
|
-
instance_variables.each do |v|
|
64
|
-
if force or not obj.instance_variables.include? v
|
65
|
-
obj.instance_variable_set(v, instance_variable_get(v))
|
66
|
-
end
|
67
|
-
end
|
68
|
-
obj
|
69
|
-
end
|
70
|
-
alias :ivs_send :instance_variables_send
|
71
|
-
end
|
72
|
-
|