bike 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,7 @@ You can make various apps such like blog, forum, contact form by putting single
5
5
 
6
6
  == Wiki
7
7
 
8
- http://wiki.github.com/afunai/bike/
8
+ http://github.com/afunai/bike/wiki
9
9
 
10
10
  == Features
11
11
 
@@ -107,7 +107,7 @@ See the URL:
107
107
  http://localhost:9292/fab/
108
108
 
109
109
  You have just created your first app. Open a bottle of your favorite drink and make yourself comfortable.
110
- When you need more complicated tricks, HTMLs under skin/examples/ will be your help. Also, you should check out the wiki: http://wiki.github.com/afunai/bike/
110
+ When you need more complicated tricks, HTMLs under skin/examples/ will be your help. Also, you should check out the wiki: http://github.com/afunai/bike/wiki
111
111
 
112
112
  == Note on Patches/Pull Requests
113
113
 
@@ -111,6 +111,10 @@ class Bike::Field
111
111
  roles
112
112
  end
113
113
 
114
+ def workflow
115
+ @workflow ||= Bike::Workflow.instance self
116
+ end
117
+
114
118
  def permit?(action)
115
119
  return false if action == :create && @result == :load
116
120
  return true unless my[:sd]
@@ -0,0 +1,89 @@
1
+ # encoding: UTF-8
2
+
3
+ # Author:: Akira FUNAI
4
+ # Copyright:: Copyright (c) 2009 Akira FUNAI
5
+
6
+ module Bike::Response
7
+
8
+ module_function
9
+
10
+ def ok(result = {})
11
+ body = result[:body].to_s
12
+ return not_found(result) if body.empty?
13
+ [
14
+ 200,
15
+ (
16
+ result[:headers] ||
17
+ {
18
+ 'Content-Type' => 'text/html',
19
+ 'Content-Length' => body.size.to_s,
20
+ }
21
+ ),
22
+ [body],
23
+ ]
24
+ end
25
+
26
+ def no_content(result = {})
27
+ [
28
+ 204,
29
+ (result[:headers] || {}),
30
+ []
31
+ ]
32
+ end
33
+
34
+ def see_other(result = {})
35
+ body = <<_html
36
+ <a href="#{result[:location]}">see other</a>
37
+ _html
38
+ [
39
+ 303,
40
+ {
41
+ 'Content-Type' => 'text/html',
42
+ 'Content-Length' => body.size.to_s,
43
+ 'Location' => result[:location],
44
+ },
45
+ [body]
46
+ ]
47
+ end
48
+
49
+ def forbidden(result = {})
50
+ body = result[:body] || 'Forbidden'
51
+ [
52
+ 403,
53
+ {
54
+ 'Content-Type' => 'text/html',
55
+ 'Content-Length' => body.size.to_s,
56
+ },
57
+ [body],
58
+ ]
59
+ end
60
+
61
+ def not_found(result = {})
62
+ body = result[:body] || 'Not Found'
63
+ [
64
+ 404,
65
+ {
66
+ 'Content-Type' => 'text/html',
67
+ 'Content-Length' => body.size.to_s,
68
+ },
69
+ [body]
70
+ ]
71
+ end
72
+
73
+ def unprocessable_entity(result = {})
74
+ body = result[:body].to_s
75
+ return not_found(result) if body.empty?
76
+ [
77
+ 422,
78
+ (
79
+ result[:headers] ||
80
+ {
81
+ 'Content-Type' => 'text/html',
82
+ 'Content-Length' => body.size.to_s,
83
+ }
84
+ ),
85
+ [body],
86
+ ]
87
+ end
88
+
89
+ end
@@ -25,12 +25,34 @@ class Bike::Workflow
25
25
  :delete => 0b11111,
26
26
  }
27
27
 
28
- def self.instance(sd)
29
- klass = sd[:workflow].to_s.capitalize
28
+ module SD
29
+ def _get(arg)
30
+ if _hide? arg
31
+ # hidden
32
+ elsif arg[:action] == :create
33
+ item_instance '_001'
34
+ _get_by_tmpl({:action => :create, :conds => {:id => '_001'}}, my[:tmpl][:index])
35
+ else
36
+ super
37
+ end
38
+ end
39
+
40
+ def _get_by_self_reference(arg)
41
+ super unless _hide? arg
42
+ end
43
+
44
+ def _hide?(arg)
45
+ (arg[:p_action] && arg[:p_action] != :read) ||
46
+ (arg[:orig_action] == :read && arg[:action] == :submit)
47
+ end
48
+ end
49
+
50
+ def self.instance(f)
51
+ klass = (f[:sd] && f[:sd][:workflow]).to_s.capitalize
30
52
  if klass != ''
31
- self.const_get(klass).new sd
53
+ self.const_get(klass).new f
32
54
  else
33
- self.new sd
55
+ self.new f
34
56
  end
35
57
  end
36
58
 
@@ -40,16 +62,56 @@ class Bike::Workflow
40
62
  }.collect{|r| Bike::I18n._ r }
41
63
  end
42
64
 
43
- attr_reader :sd
65
+ attr_reader :f
44
66
 
45
- def initialize(sd)
46
- @sd = sd
67
+ def initialize(f)
68
+ @f = f
47
69
  end
48
70
 
49
71
  def default_sub_items
50
72
  self.class.const_get :DEFAULT_SUB_ITEMS
51
73
  end
52
74
 
75
+ def default_meta
76
+ self.class.const_get :DEFAULT_META
77
+ end
78
+
79
+ def sd_module
80
+ self.class.const_get :SD
81
+ end
82
+
83
+ def call(method, params)
84
+ (method == 'post') ? post(params) : get(params)
85
+ rescue Bike::Error::Forbidden
86
+ if params[:action] && Bike.client == 'nobody'
87
+ params[:dest_action] ||= (method == 'post') ? :index : params[:action]
88
+ params[:action] = :login
89
+ end
90
+ Bike::Response.unprocessable_entity(:body => __g_default(params)) rescue Bike::Response.forbidden
91
+ # TODO: rescue Error::System etc.
92
+ end
93
+
94
+ def get(params)
95
+ if @f.is_a? Bike::File
96
+ body = (params[:sub_action] == :small) ? @f.thumbnail : @f.body
97
+ Bike::Response.ok(
98
+ :headers => {
99
+ 'Content-Type' => @f.val['type'],
100
+ 'Content-Length' => body.to_s.size.to_s,
101
+ },
102
+ :body => body
103
+ )
104
+ else
105
+ m = "_g_#{params[:action]}"
106
+ respond_to?(m, true) ? __send__(m, params) : _g_default(params)
107
+ end
108
+ end
109
+
110
+ def post(params)
111
+ m = "_p_#{params[:action]}"
112
+ respond_to?(m, true) ? __send__(m, params) : _p_default(params)
113
+ end
114
+
53
115
  def permit?(roles, action)
54
116
  case action
55
117
  when :login, :done, :message
@@ -62,28 +124,139 @@ class Bike::Workflow
62
124
  end
63
125
  end
64
126
 
65
- def _get(arg)
66
- @sd.instance_eval {
67
- if arg[:action] == :create
68
- item_instance '_001'
69
- _get_by_tmpl({:action => :create, :conds => {:id => '_001'}}, my[:tmpl][:index])
127
+ private
128
+
129
+ def _g_default(params)
130
+ Bike::Response.ok :body => __g_default(params)
131
+ end
132
+
133
+ def __g_default(params)
134
+ f = @f
135
+ params[:action] ||= f.default_action
136
+ until f.is_a? Bike::Set::Static::Folder
137
+ params = {
138
+ :action => (f.default_action == :read) ? :read : nil,
139
+ :sub_action => f.send(:summary?, params) ? nil : (params[:sub_action] || :detail),
140
+ f[:id] => params,
141
+ }
142
+ params[:conds] = {:id => f[:id]} if f[:parent].is_a? Bike::Set::Dynamic
143
+ f = f[:parent]
144
+ end if f.is_a? Bike::Set::Dynamic
145
+
146
+ f.get(params)
147
+ end
148
+
149
+ def _p_default(params)
150
+ res = __p_validate params
151
+ return res if res
152
+
153
+ __p_set_transaction
154
+ __p_update params
155
+
156
+ if params[:status]
157
+ if @f[:folder].commit :persistent
158
+ Bike.transaction[@f[:tid]] = __p_result_summary
159
+ id_step = __p_result_step(params) if @f[:parent] == @f[:folder] && __p_next_action != :done
160
+ Bike::Response.see_other(
161
+ :location => "#{Bike.uri}/#{@f[:tid]}#{@f[:path]}/#{id_step}#{__p_next_action}.html"
162
+ )
163
+ else
164
+ params = {:action => :update}
165
+ params[:conds] = {:id => @f.errors.keys}
166
+ Bike::Response.unprocessable_entity :body => __g_default(params)
70
167
  end
71
- }
168
+ else
169
+ @f.commit :temp
170
+ id_step = __p_result_step(params)
171
+ Bike::Response.see_other(
172
+ :location => "#{Bike.uri}/#{@f[:tid]}/#{id_step}update.html"
173
+ )
174
+ end
72
175
  end
73
176
 
74
- def _hide?(arg)
75
- (arg[:p_action] && arg[:p_action] != :read) ||
76
- (arg[:orig_action] == :read && arg[:action] == :submit)
177
+ def _p_preview(params)
178
+ res = __p_validate params
179
+ return res if res
180
+
181
+ __p_set_transaction
182
+ __p_update params
183
+
184
+ if @f.commit(:temp) || params[:sub_action] == :delete
185
+ id_step = __p_result_step(params)
186
+ action = "preview_#{params[:sub_action]}"
187
+ Bike::Response.see_other(
188
+ :location => "#{Bike.uri}/#{@f[:tid]}/#{id_step}#{action}.html"
189
+ )
190
+ else
191
+ params = {:action => :update}
192
+ params[:conds] = {:id => @f.errors.keys}
193
+ Bike::Response.unprocessable_entity(:body => __g_default(params))
194
+ end
77
195
  end
78
196
 
79
- def before_commit
197
+ def _p_login(params)
198
+ user = Bike::Set::Static::Folder.root.item('_users', 'main', params['id'].to_s)
199
+ if user && params['pw'].to_s.crypt(user.val('password')) == user.val('password')
200
+ Bike.client = params['id']
201
+ else
202
+ Bike.client = nil
203
+ raise Bike::Error::Forbidden
204
+ end
205
+ path = Bike::Path.path_of params[:conds]
206
+ action = (params[:dest_action] =~ /\A\w+\z/) ? params[:dest_action] : 'index'
207
+ Bike::Response.see_other(
208
+ :location => "#{Bike.uri}#{@f[:path]}/#{path}#{action}.html"
209
+ )
80
210
  end
81
211
 
82
- def after_commit
212
+ def _p_logout(params)
213
+ return Bike::Response.forbidden(:body => 'invalid token') unless params[:token] == Bike.token
214
+
215
+ Bike.client = nil
216
+ path = Bike::Path.path_of params[:conds]
217
+ Bike::Response.see_other(
218
+ :location => "#{Bike.uri}#{@f[:path]}/#{path}index.html"
219
+ )
220
+ end
221
+ alias :_g_logout :_p_logout
222
+
223
+ def __p_validate(params)
224
+ if params[:token] != Bike.token
225
+ Bike::Response.forbidden(:body => 'invalid token')
226
+ elsif Bike.transaction[@f[:tid]] && !Bike.transaction[@f[:tid]].is_a?(Bike::Field)
227
+ Bike::Response.unprocessable_entity(:body => 'transaction expired')
228
+ end
229
+ end
230
+
231
+ def __p_set_transaction
232
+ Bike.transaction[@f[:tid]] ||= @f if @f[:tid] =~ Bike::REX::TID
233
+ end
234
+
235
+ def __p_update(params)
236
+ @f.update params
237
+ end
238
+
239
+ def __p_result_summary
240
+ (@f.result || {}).values.inject({}) {|summary, item|
241
+ item_result = item.result.is_a?(::Symbol) ? item.result : :update
242
+ summary[item_result] = summary[item_result].to_i + 1
243
+ summary
244
+ }
245
+ end
246
+
247
+ def __p_result_step(params)
248
+ if @f.result
249
+ id = @f.result.values.collect {|item| item[:id] }
250
+ else
251
+ id = params.keys.select {|id|
252
+ id.is_a?(::String) && (id[Bike::REX::ID] || id[Bike::REX::ID_NEW])
253
+ }
254
+ end
255
+ Bike::Path.path_of(:id => id)
83
256
  end
84
257
 
85
- def next_action(base)
86
- (!base.result || base.result.values.all? {|item| item.permit? :read }) ? :read_detail : :done
258
+ def __p_next_action
259
+ (!@f.result || @f.result.values.all? {|item| item.permit? :read }) ? :read_detail : :done
87
260
  end
88
261
 
89
262
  end
@@ -17,14 +17,11 @@ class Bike::Workflow::Attachment < Bike::Workflow
17
17
  :delete => 0b00000,
18
18
  }
19
19
 
20
- def permit?(roles, action)
21
- (action == :login) ||
22
- (@sd[:parent] && @sd[:parent].permit?(action))
23
- end
24
-
25
- def _get(arg)
26
- @sd.instance_eval {
27
- if arg[:action] == :create || arg[:action] == :update
20
+ module SD
21
+ def _get(arg)
22
+ if _hide? arg
23
+ # hidden
24
+ elsif arg[:action] == :create || arg[:action] == :update
28
25
  new_item = item_instance '_001'
29
26
 
30
27
  item_outs = _g_default(arg) {|item, item_arg|
@@ -39,12 +36,23 @@ _html
39
36
  }
40
37
  tmpl = my[:tmpl][:index].gsub('$()', item_outs)
41
38
  _get_by_tmpl({:p_action => arg[:p_action], :action => :update}, tmpl)
39
+ else
40
+ super
42
41
  end
43
- }
42
+ end
43
+
44
+ def _get_by_self_reference(arg)
45
+ super unless _hide? arg
46
+ end
47
+
48
+ def _hide?(arg)
49
+ arg[:action] == :submit
50
+ end
44
51
  end
45
52
 
46
- def _hide?(arg)
47
- arg[:action] == :submit
53
+ def permit?(roles, action)
54
+ (action == :login) ||
55
+ (@f[:parent] && @f[:parent].permit?(action))
48
56
  end
49
57
 
50
58
  end
@@ -24,15 +24,18 @@ class Bike::Workflow::Register < Bike::Workflow
24
24
  :delete => 0b11100,
25
25
  }
26
26
 
27
- def before_commit
28
- @sd.send(:pending_items).each {|id, item|
27
+ private
28
+
29
+ def __p_update(params)
30
+ super
31
+ @f.send(:pending_items).each {|id, item|
29
32
  if id =~ Bike::REX::ID_NEW
30
33
  item.item('_owner').instance_variable_set(:@val, item.item('_id').val)
31
34
  end
32
35
  }
33
36
  end
34
37
 
35
- def next_action(base)
38
+ def __p_next_action
36
39
  (Bike.client == 'nobody') ? :done : super
37
40
  end
38
41
 
@@ -114,158 +114,16 @@ class Bike
114
114
  else
115
115
  base = Bike::Path.base_of path
116
116
  end
117
- return response_not_found unless base
117
+ return Bike::Response.not_found unless base
118
118
 
119
119
  base[:tid] = tid
120
120
  Bike.current[:base] = base
121
121
 
122
- begin
123
- if params[:action] == :logout && params[:token] == Bike.token
124
- logout(base, params)
125
- elsif method == 'get'
126
- get(base, params)
127
- elsif params[:action] == :login
128
- login(base, params)
129
- elsif params[:action] == :preview
130
- preview(base, params)
131
- elsif params[:token] != Bike.token
132
- response_forbidden(:body => 'invalid token')
133
- elsif Bike.transaction[tid] && !Bike.transaction[tid].is_a?(Bike::Field)
134
- response_unprocessable_entity(:body => 'transaction expired')
135
- else
136
- begin
137
- post(base, params)
138
- rescue Bike::Error::Forbidden
139
- response_forbidden
140
- end
141
- end
142
- rescue Bike::Error::Forbidden
143
- if params[:action] && Bike.client == 'nobody'
144
- params[:dest_action] = (method == 'post') ? :index : params[:action]
145
- params[:action] = :login
146
- end
147
- response_unprocessable_entity(:body => _get(base, params)) rescue response_forbidden
148
- # TODO: rescue Error::System etc.
149
- end
122
+ base.workflow.call(method, params)
150
123
  end
151
124
 
152
125
  private
153
126
 
154
- def login(base, params)
155
- user = Bike::Set::Static::Folder.root.item('_users', 'main', params['id'].to_s)
156
- if user && params['pw'].to_s.crypt(user.val('password')) == user.val('password')
157
- Bike.client = params['id']
158
- else
159
- Bike.client = nil
160
- raise Bike::Error::Forbidden
161
- end
162
- path = Bike::Path.path_of params[:conds]
163
- action = (params['dest_action'] =~ /\A\w+\z/) ? params['dest_action'] : 'index'
164
- response_see_other(
165
- :location => "#{Bike.uri}#{base[:path]}/#{path}#{action}.html"
166
- )
167
- end
168
-
169
- def logout(base, params)
170
- Bike.client = nil
171
- path = Bike::Path.path_of params[:conds]
172
- response_see_other(
173
- :location => "#{Bike.uri}#{base[:path]}/#{path}index.html"
174
- )
175
- end
176
-
177
- def get(base, params)
178
- if base.is_a? Bike::File
179
- body = (params[:sub_action] == :small) ? base.thumbnail : base.body
180
- response_ok(
181
- :headers => {
182
- 'Content-Type' => base.val['type'],
183
- 'Content-Length' => body.to_s.size.to_s,
184
- },
185
- :body => body
186
- )
187
- else
188
- response_ok :body => _get(base, params)
189
- end
190
- end
191
-
192
- def preview(base, params)
193
- Bike.transaction[base[:tid]] ||= base if base[:tid] =~ Bike::REX::TID
194
-
195
- base.update params
196
- if base.commit(:temp) || params[:sub_action] == :delete
197
- id_step = result_step(base, params)
198
- action = "preview_#{params[:sub_action]}"
199
- response_see_other(
200
- :location => "#{Bike.uri}/#{base[:tid]}/#{id_step}#{action}.html"
201
- )
202
- else
203
- params = {:action => :update}
204
- params[:conds] = {:id => base.errors.keys}
205
- return response_unprocessable_entity(:body => _get(base, params))
206
- end
207
- end
208
-
209
- def post(base, params)
210
- Bike.transaction[base[:tid]] ||= base if base[:tid] =~ Bike::REX::TID
211
-
212
- base.update params
213
- if params[:status]
214
- if base[:folder].commit :persistent
215
- Bike.transaction[base[:tid]] = result_summary base
216
- action = base.workflow.next_action base
217
- id_step = result_step(base, params) if base[:parent] == base[:folder] && action != :done
218
- response_see_other(
219
- :location => "#{Bike.uri}/#{base[:tid]}#{base[:path]}/#{id_step}#{action}.html"
220
- )
221
- else
222
- params = {:action => :update}
223
- params[:conds] = {:id => base.errors.keys}
224
- response_unprocessable_entity :body => _get(base, params)
225
- end
226
- else
227
- base.commit :temp
228
- id_step = result_step(base, params)
229
- response_see_other(
230
- :location => "#{Bike.uri}/#{base[:tid]}/#{id_step}update.html"
231
- )
232
- end
233
- end
234
-
235
- def result_summary(base)
236
- (base.result || {}).values.inject({}) {|summary, item|
237
- item_result = item.result.is_a?(::Symbol) ? item.result : :update
238
- summary[item_result] = summary[item_result].to_i + 1
239
- summary
240
- }
241
- end
242
-
243
- def result_step(base, params)
244
- if base.result
245
- id = base.result.values.collect {|item| item[:id] }
246
- else
247
- id = params.keys.select {|id|
248
- id.is_a?(::String) && (id[Bike::REX::ID] || id[Bike::REX::ID_NEW])
249
- }
250
- end
251
- Bike::Path.path_of(:id => id)
252
- end
253
-
254
- def _get(f, params)
255
- params[:action] ||= f.default_action
256
- until f.is_a? Bike::Set::Static::Folder
257
- params = {
258
- :action => (f.default_action == :read) ? :read : nil,
259
- :sub_action => f.send(:summary?, params) ? nil : (params[:sub_action] || :detail),
260
- f[:id] => params,
261
- }
262
- params[:conds] = {:id => f[:id]} if f[:parent].is_a? Bike::Set::Dynamic
263
- f = f[:parent]
264
- end if f.is_a? Bike::Set::Dynamic
265
-
266
- f.get params
267
- end
268
-
269
127
  def params_from_request(req)
270
128
  params = {
271
129
  :action => Bike::Path.action_of(req.path_info),
@@ -306,6 +164,8 @@ class Bike
306
164
  hash[item_id][:self] = val
307
165
  elsif item_id == '_token'
308
166
  hash[:token] = val
167
+ elsif item_id == 'dest_action'
168
+ hash[:dest_action] = val
309
169
  else
310
170
  hash[item_id] = val
311
171
  end
@@ -314,83 +174,4 @@ class Bike
314
174
  }
315
175
  end
316
176
 
317
- def response_ok(result = {})
318
- body = result[:body].to_s
319
- return response_not_found(result) if body.empty?
320
- [
321
- 200,
322
- (
323
- result[:headers] ||
324
- {
325
- 'Content-Type' => 'text/html',
326
- 'Content-Length' => body.size.to_s,
327
- }
328
- ),
329
- [body],
330
- ]
331
- end
332
-
333
- def response_no_content(result = {})
334
- [
335
- 204,
336
- (result[:headers] || {}),
337
- []
338
- ]
339
- end
340
-
341
- def response_see_other(result = {})
342
- body = <<_html
343
- <a href="#{result[:location]}">see other</a>
344
- _html
345
- [
346
- 303,
347
- {
348
- 'Content-Type' => 'text/html',
349
- 'Content-Length' => body.size.to_s,
350
- 'Location' => result[:location],
351
- },
352
- [body]
353
- ]
354
- end
355
-
356
- def response_forbidden(result = {})
357
- body = result[:body] || 'Forbidden'
358
- [
359
- 403,
360
- {
361
- 'Content-Type' => 'text/html',
362
- 'Content-Length' => body.size.to_s,
363
- },
364
- [body],
365
- ]
366
- end
367
-
368
- def response_not_found(result = {})
369
- body = result[:body] || 'Not Found'
370
- [
371
- 404,
372
- {
373
- 'Content-Type' => 'text/html',
374
- 'Content-Length' => body.size.to_s,
375
- },
376
- [body]
377
- ]
378
- end
379
-
380
- def response_unprocessable_entity(result = {})
381
- body = result[:body].to_s
382
- return response_not_found(result) if body.empty?
383
- [
384
- 422,
385
- (
386
- result[:headers] ||
387
- {
388
- 'Content-Type' => 'text/html',
389
- 'Content-Length' => body.size.to_s,
390
- }
391
- ),
392
- [body],
393
- ]
394
- end
395
-
396
177
  end
@@ -7,20 +7,21 @@ class Bike::Set::Dynamic < Bike::Field
7
7
 
8
8
  include Bike::Set
9
9
 
10
- attr_reader :storage, :workflow
10
+ attr_reader :storage
11
11
 
12
12
  def initialize(meta = {})
13
13
  @meta = meta
14
14
  @storage = Bike::Storage.instance self
15
- @workflow = Bike::Workflow.instance self
16
- @meta = @workflow.class.const_get(:DEFAULT_META).merge @meta
15
+ @meta = workflow.default_meta.merge @meta
17
16
  @item_object = {}
18
17
 
18
+ self.extend workflow.sd_module
19
+
19
20
  my[:item] ||= {
20
21
  'default' => {:item => {}}
21
22
  }
22
23
  my[:item].each {|type, item_meta|
23
- item_meta[:item] = @workflow.default_sub_items.merge item_meta[:item]
24
+ item_meta[:item] = workflow.default_sub_items.merge item_meta[:item]
24
25
  }
25
26
 
26
27
  my[:p_size] = meta[:max] if meta[:max]
@@ -50,8 +51,6 @@ class Bike::Set::Dynamic < Bike::Field
50
51
  end
51
52
 
52
53
  def commit(type = :temp)
53
- @workflow.before_commit
54
-
55
54
  items = pending_items
56
55
  items.each {|id, item|
57
56
  item.commit(:temp) || next
@@ -66,7 +65,6 @@ class Bike::Set::Dynamic < Bike::Field
66
65
  if valid?
67
66
  @result = (@action == :update) ? items : @action
68
67
  @action = nil if type == :persistent
69
- @workflow.after_commit
70
68
  self
71
69
  end
72
70
  end
@@ -77,10 +75,6 @@ class Bike::Set::Dynamic < Bike::Field
77
75
  @storage.val
78
76
  end
79
77
 
80
- def _get(arg)
81
- (@workflow._get(arg) || super) unless @workflow._hide? arg
82
- end
83
-
84
78
  def _get_by_tmpl(arg, tmpl = '')
85
79
  if arg[:action] == :read || self != Bike.base
86
80
  super
@@ -95,10 +89,6 @@ _html
95
89
  end
96
90
  end
97
91
 
98
- def _get_by_self_reference(arg)
99
- super unless @workflow._hide?(arg)
100
- end
101
-
102
92
  def permit_get?(arg)
103
93
  permit?(arg[:action]) || collect_item(arg[:conds] || {}).all? {|item|
104
94
  item[:id][Bike::REX::ID_NEW] ?
@@ -2,7 +2,7 @@
2
2
  <head><title>@(label)</title></head>
3
3
  <body>
4
4
  <h1>@(label)</h1>
5
- <dl id="main" class="app-blog">
5
+ <dl id="main" class="app-register">
6
6
  <dt>id: $(_id = meta-id 32 1..32)</dt>
7
7
  <dd>
8
8
  password: $(password = password 12)
@@ -87,6 +87,21 @@ class TC_Bike < Test::Unit::TestCase
87
87
  'Bike#rebuild_params should rebuild both the special symbols and regular items'
88
88
  )
89
89
 
90
+ hash = bike.instance_eval {
91
+ rebuild_params(
92
+ '_token' => 'foo',
93
+ 'dest_action' => 'bar'
94
+ )
95
+ }
96
+ assert_equal(
97
+ {
98
+ :token => 'foo',
99
+ :dest_action => 'bar',
100
+ },
101
+ hash,
102
+ 'Bike#rebuild_params should use symbols for special keys'
103
+ )
104
+
90
105
  hash = bike.instance_eval {
91
106
  rebuild_params(
92
107
  'moo.conds-p' => '9',
@@ -648,115 +663,6 @@ class TC_Bike < Test::Unit::TestCase
648
663
  )
649
664
  end
650
665
 
651
- def test_login
652
- Bike.client = nil
653
- res = Bike.new.send(
654
- :login,
655
- Bike::Set::Static::Folder.root.item('foo', 'main'),
656
- {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}, 'dest_action' => 'update'}
657
- )
658
- assert_equal(
659
- 'test',
660
- Bike.client,
661
- 'Bike#login should set Bike.client given a valid pair of user/password'
662
- )
663
- assert_match(
664
- %r{/foo/20100222/123/update.html},
665
- res[1]['Location'],
666
- 'Bike#login should return a proper location header'
667
- )
668
- end
669
-
670
- def test_login_default_action
671
- Bike.client = nil
672
- res = Bike.new.send(
673
- :login,
674
- Bike::Set::Static::Folder.root.item('foo', 'main'),
675
- {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
676
- )
677
- assert_match(
678
- %r{/foo/20100222/123/index.html},
679
- res[1]['Location'],
680
- "Bike#login should set 'index' as the default action of a location"
681
- )
682
- end
683
-
684
- def test_login_with_wrong_account
685
- Bike.client = nil
686
-
687
- assert_raise(
688
- Bike::Error::Forbidden,
689
- 'Bike#login should raise Error::Forbidden given a non-existent user'
690
- ) {
691
- Bike.new.send(
692
- :login,
693
- Bike::Set::Static::Folder.root.item('foo', 'main'),
694
- {'id' => 'non-existent', 'pw' => 'test'}
695
- )
696
- }
697
- assert_equal(
698
- 'nobody',
699
- Bike.client,
700
- 'Bike#login should not set Bike.client with a non-existent user'
701
- )
702
-
703
- assert_raise(
704
- Bike::Error::Forbidden,
705
- 'Bike#login should raise Error::Forbidden given a empty password'
706
- ) {
707
- Bike.new.send(
708
- :login,
709
- Bike::Set::Static::Folder.root.item('foo', 'main'),
710
- {'id' => 'test', 'pw' => nil}
711
- )
712
- }
713
- assert_equal(
714
- 'nobody',
715
- Bike.client,
716
- 'Bike#login should not set Bike.client with an empty password'
717
- )
718
-
719
- assert_raise(
720
- Bike::Error::Forbidden,
721
- 'Bike#login should raise Error::Forbidden given a wrong password'
722
- ) {
723
- res = Bike.new.send(
724
- :login,
725
- Bike::Set::Static::Folder.root.item('foo', 'main'),
726
- {
727
- 'id' => 'test',
728
- 'pw' => 'wrong',
729
- :conds => {:id => '20100222_0123'},
730
- 'dest_action' => 'update'
731
- }
732
- )
733
- }
734
- assert_equal(
735
- 'nobody',
736
- Bike.client,
737
- 'Bike#login should not set Bike.client with a wrong password'
738
- )
739
- end
740
-
741
- def test_logout
742
- Bike.client = 'frank'
743
- res = Bike.new.send(
744
- :logout,
745
- Bike::Set::Static::Folder.root.item('foo', 'main'),
746
- {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
747
- )
748
- assert_equal(
749
- 'nobody',
750
- Bike.client,
751
- 'Bike#logout should clear Bike.client'
752
- )
753
- assert_match(
754
- %r{/foo/20100222/123/index.html},
755
- res[1]['Location'],
756
- 'Bike#logout should return a proper location header'
757
- )
758
- end
759
-
760
666
  def test_libdir
761
667
  assert_match(
762
668
  %r{^.*/lib$},
@@ -772,7 +772,7 @@ _html
772
772
  res = Rack::MockRequest.new(@bike).post(
773
773
  "http://#{base_uri}/t_store/main/update.html",
774
774
  {
775
- :input => ".action-preview_update=submit&_1-name=fz&_1-comment=howdy.&.status-public=create"
775
+ :input => ".action-preview_update=submit&_1-name=fz&_1-comment=howdy.&.status-public=create&_token=#{Bike.token}"
776
776
  }
777
777
  )
778
778
  tid = res.headers['Location'][Bike::REX::TID]
@@ -861,7 +861,7 @@ _html
861
861
  res = Rack::MockRequest.new(@bike).post(
862
862
  'http://example.com/t_store/main/update.html',
863
863
  {
864
- :input => ".action-preview_update=submit&_1-name=verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrylong&_1-comment=howdy.&.status-public=create"
864
+ :input => ".action-preview_update=submit&_1-name=verrrrrrrrrrrrrrrrrrrrrrrrrrrrrrylong&_1-comment=howdy.&.status-public=create&_token=#{Bike.token}"
865
865
  }
866
866
  )
867
867
  assert_equal(
@@ -1054,6 +1054,16 @@ _html
1054
1054
  res.status,
1055
1055
  'Bike#call with :login action should return status 422 upon failure'
1056
1056
  )
1057
+ assert_match(
1058
+ /^<html/,
1059
+ res.body,
1060
+ 'Bike#call with :login action should return login form upon failure'
1061
+ )
1062
+ assert_match(
1063
+ /name="dest_action" value="update"/,
1064
+ res.body,
1065
+ 'Bike#call with :login action should keep the dest_action upon failure'
1066
+ )
1057
1067
  end
1058
1068
 
1059
1069
  def test_post_logout
@@ -1278,4 +1288,26 @@ _html
1278
1288
  )
1279
1289
  end
1280
1290
 
1291
+ def test_workflow_register
1292
+ Bike.client = nil
1293
+ Bike::Set::Static::Folder.root.item('_users', 'main').storage.delete('00000000_don')
1294
+
1295
+ res = Rack::MockRequest.new(@bike).post(
1296
+ 'http://example.com/_users/main/update.html',
1297
+ {
1298
+ :input => "_1-_id=don&_1-password=secret&.status-public=create&_token=#{Bike.token}"
1299
+ }
1300
+ )
1301
+ assert_match(
1302
+ /done\.html$/,
1303
+ res.headers['Location'],
1304
+ 'Workflow::Register should have special __p_next_action().'
1305
+ )
1306
+ assert_equal(
1307
+ 'don',
1308
+ Bike::Set::Static::Folder.root.item('_users', 'main', 'don')[:owner],
1309
+ 'Workflow::Register should set special item[:owner]'
1310
+ )
1311
+ end
1312
+
1281
1313
  end
@@ -38,8 +38,8 @@ class TC_Workflow < Test::Unit::TestCase
38
38
 
39
39
  assert_equal(
40
40
  sd,
41
- Bike::Workflow.instance(sd).sd,
42
- 'Bike::Workflow.instance should set @sd'
41
+ Bike::Workflow.instance(sd).f,
42
+ 'Bike::Workflow.instance should set @f'
43
43
  )
44
44
  end
45
45
 
@@ -364,4 +364,107 @@ class TC_Workflow < Test::Unit::TestCase
364
364
  )
365
365
  end
366
366
 
367
+ def test_login
368
+ Bike.client = nil
369
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
370
+ :_p_login,
371
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}, :dest_action => 'update'}
372
+ )
373
+ assert_equal(
374
+ 'test',
375
+ Bike.client,
376
+ 'Bike#login should set Bike.client given a valid pair of user/password'
377
+ )
378
+ assert_match(
379
+ %r{/foo/20100222/123/update.html},
380
+ res[1]['Location'],
381
+ 'Bike#login should return a proper location header'
382
+ )
383
+ end
384
+
385
+ def test_login_default_action
386
+ Bike.client = nil
387
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
388
+ :_p_login,
389
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}}
390
+ )
391
+ assert_match(
392
+ %r{/foo/20100222/123/index.html},
393
+ res[1]['Location'],
394
+ "Bike#login should set 'index' as the default action of a location"
395
+ )
396
+ end
397
+
398
+ def test_login_with_wrong_account
399
+ Bike.client = nil
400
+
401
+ assert_raise(
402
+ Bike::Error::Forbidden,
403
+ 'Bike#login should raise Error::Forbidden given a non-existent user'
404
+ ) {
405
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
406
+ :_p_login,
407
+ {'id' => 'non-existent', 'pw' => 'test'}
408
+ )
409
+ }
410
+ assert_equal(
411
+ 'nobody',
412
+ Bike.client,
413
+ 'Bike#login should not set Bike.client with a non-existent user'
414
+ )
415
+
416
+ assert_raise(
417
+ Bike::Error::Forbidden,
418
+ 'Bike#login should raise Error::Forbidden given a empty password'
419
+ ) {
420
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
421
+ :_p_login,
422
+ {'id' => 'test', 'pw' => nil}
423
+ )
424
+ }
425
+ assert_equal(
426
+ 'nobody',
427
+ Bike.client,
428
+ 'Bike#login should not set Bike.client with an empty password'
429
+ )
430
+
431
+ assert_raise(
432
+ Bike::Error::Forbidden,
433
+ 'Bike#login should raise Error::Forbidden given a wrong password'
434
+ ) {
435
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
436
+ :_p_login,
437
+ {
438
+ 'id' => 'test',
439
+ 'pw' => 'wrong',
440
+ :conds => {:id => '20100222_0123'},
441
+ :dest_action => 'update'
442
+ }
443
+ )
444
+ }
445
+ assert_equal(
446
+ 'nobody',
447
+ Bike.client,
448
+ 'Bike#login should not set Bike.client with a wrong password'
449
+ )
450
+ end
451
+
452
+ def test_logout
453
+ Bike.client = 'frank'
454
+ res = Bike::Set::Static::Folder.root.item('foo', 'main').workflow.send(
455
+ :_p_logout,
456
+ {'id' => 'test', 'pw' => 'test', :conds => {:id => '20100222_0123'}, :token => Bike.token}
457
+ )
458
+ assert_equal(
459
+ 'nobody',
460
+ Bike.client,
461
+ 'Bike#logout should clear Bike.client'
462
+ )
463
+ assert_match(
464
+ %r{/foo/20100222/123/index.html},
465
+ res[1]['Location'],
466
+ 'Bike#logout should return a proper location header'
467
+ )
468
+ end
469
+
367
470
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 2
8
- - 1
9
- version: 0.2.1
8
+ - 2
9
+ version: 0.2.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Akira FUNAI
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-09-20 00:00:00 +09:00
17
+ date: 2010-10-12 00:00:00 +09:00
18
18
  default_executable: bike
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -146,6 +146,7 @@ files:
146
146
  - lib/_i18n.rb
147
147
  - lib/_parser.rb
148
148
  - lib/_path.rb
149
+ - lib/_response.rb
149
150
  - lib/_storage/_storage.rb
150
151
  - lib/_storage/file.rb
151
152
  - lib/_storage/sequel.rb