bike 0.2.1
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/LICENSE +19 -0
- data/README.rdoc +124 -0
- data/bin/bike +35 -0
- data/lib/_error.rb +14 -0
- data/lib/_field.rb +260 -0
- data/lib/_i18n.rb +144 -0
- data/lib/_parser.rb +256 -0
- data/lib/_path.rb +86 -0
- data/lib/_storage/_storage.rb +215 -0
- data/lib/_storage/file.rb +201 -0
- data/lib/_storage/sequel.rb +174 -0
- data/lib/_storage/temp.rb +73 -0
- data/lib/_widget/action_create.rb +23 -0
- data/lib/_widget/action_login.rb +22 -0
- data/lib/_widget/action_signup.rb +16 -0
- data/lib/_widget/action_update.rb +16 -0
- data/lib/_widget/crumb.rb +24 -0
- data/lib/_widget/done.rb +16 -0
- data/lib/_widget/login.rb +25 -0
- data/lib/_widget/me.rb +31 -0
- data/lib/_widget/message.rb +51 -0
- data/lib/_widget/navi.rb +88 -0
- data/lib/_widget/submit.rb +49 -0
- data/lib/_widget/view_ym.rb +77 -0
- data/lib/_workflow/_workflow.rb +89 -0
- data/lib/_workflow/attachment.rb +50 -0
- data/lib/_workflow/blog.rb +28 -0
- data/lib/_workflow/contact.rb +23 -0
- data/lib/_workflow/forum.rb +26 -0
- data/lib/_workflow/register.rb +39 -0
- data/lib/bike.rb +396 -0
- data/lib/meta/_meta.rb +20 -0
- data/lib/meta/group.rb +19 -0
- data/lib/meta/id.rb +59 -0
- data/lib/meta/owner.rb +21 -0
- data/lib/meta/timestamp.rb +118 -0
- data/lib/scalar/checkbox.rb +68 -0
- data/lib/scalar/file.rb +144 -0
- data/lib/scalar/img.rb +112 -0
- data/lib/scalar/password.rb +58 -0
- data/lib/scalar/radio.rb +47 -0
- data/lib/scalar/select.rb +47 -0
- data/lib/scalar/text.rb +38 -0
- data/lib/scalar/textarea.rb +35 -0
- data/lib/scalar/textarea_pre.rb +14 -0
- data/lib/scalar/textarea_wiki.rb +173 -0
- data/lib/set/_set.rb +196 -0
- data/lib/set/dynamic.rb +177 -0
- data/lib/set/static.rb +102 -0
- data/lib/set/static_folder.rb +96 -0
- data/locale/en/index.po +242 -0
- data/locale/index.pot +243 -0
- data/locale/ja/index.po +242 -0
- data/locale/lazy_parser.rb +54 -0
- data/skel/config.ru +27 -0
- data/skel/skin/_users/00000000_frank-avatar.jpg +0 -0
- data/skel/skin/_users/00000000_frank-avatar_small.jpg +0 -0
- data/skel/skin/_users/00000000_frank.yaml +12 -0
- data/skel/skin/_users/00000000_root-avatar.jpg +0 -0
- data/skel/skin/_users/00000000_root-avatar_small.jpg +0 -0
- data/skel/skin/_users/00000000_root.yaml +11 -0
- data/skel/skin/_users/css/users.css +21 -0
- data/skel/skin/_users/css/users.less +25 -0
- data/skel/skin/_users/done.html +42 -0
- data/skel/skin/_users/index.html +46 -0
- data/skel/skin/_users/index.yaml +3 -0
- data/skel/skin/_users/summary.html +40 -0
- data/skel/skin/css/base.css +93 -0
- data/skel/skin/css/base.less +139 -0
- data/skel/skin/css/coax.css +199 -0
- data/skel/skin/css/coax.less +244 -0
- data/skel/skin/examples/blog/20091214_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100630_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100630_0002.yaml +14 -0
- data/skel/skin/examples/blog/20100701_0001.yaml +8 -0
- data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f.jpg +0 -0
- data/skel/skin/examples/blog/20100701_0002-a-20100701_0001-f_small.jpg +0 -0
- data/skel/skin/examples/blog/20100701_0002.yaml +19 -0
- data/skel/skin/examples/blog/frank/20100701_0001.yaml +10 -0
- data/skel/skin/examples/blog/frank/index.yaml +4 -0
- data/skel/skin/examples/blog/index.html +51 -0
- data/skel/skin/examples/blog/rss.xml +18 -0
- data/skel/skin/examples/contact/20100701_0001-file.txt +1 -0
- data/skel/skin/examples/contact/20100701_0001.yaml +15 -0
- data/skel/skin/examples/contact/20100701_0002.yaml +8 -0
- data/skel/skin/examples/contact/20100701_0003.yaml +9 -0
- data/skel/skin/examples/contact/index.html +47 -0
- data/skel/skin/examples/contact/js/contact.js +13 -0
- data/skel/skin/examples/contact/summary.html +54 -0
- data/skel/skin/examples/forum/20100701_0001.yaml +41 -0
- data/skel/skin/examples/forum/20100701_0002.yaml +25 -0
- data/skel/skin/examples/forum/index.html +68 -0
- data/skel/skin/examples/forum/summary.html +47 -0
- data/skel/skin/examples/index.html +73 -0
- data/skel/skin/index.html +39 -0
- data/skel/skin/js/base.js +50 -0
- data/t/locale/de/index.po +19 -0
- data/t/locale/en-GB/index.po +25 -0
- data/t/locale/ja/index.po +30 -0
- data/t/skin/_users/00000000_test.yaml +3 -0
- data/t/skin/_users/index.html +13 -0
- data/t/skin/foo/20091120_0001.yaml +7 -0
- data/t/skin/foo/bar/20091120_0001.yaml +5 -0
- data/t/skin/foo/bar/index.yaml +5 -0
- data/t/skin/foo/baz/css/baz.css +1 -0
- data/t/skin/foo/css/foo.css +1 -0
- data/t/skin/foo/index.html +14 -0
- data/t/skin/foo/index.yaml +7 -0
- data/t/skin/foo/not_css/foo.css +1 -0
- data/t/skin/foo/qux/index.html +8 -0
- data/t/skin/foo/qux/moo/index.html +6 -0
- data/t/skin/foo/sub-20100306_0001.yaml +3 -0
- data/t/skin/index.yaml +3 -0
- data/t/skin/t_attachment/index.html +13 -0
- data/t/skin/t_contact/done.html +6 -0
- data/t/skin/t_contact/index.html +9 -0
- data/t/skin/t_file/index.html +16 -0
- data/t/skin/t_img/index.html +14 -0
- data/t/skin/t_img/test.jpg +0 -0
- data/t/skin/t_select/index.html +9 -0
- data/t/skin/t_store/index.html +9 -0
- data/t/skin/t_summary/20100326_0001.yaml +3 -0
- data/t/skin/t_summary/create.html +9 -0
- data/t/skin/t_summary/index.html +9 -0
- data/t/skin/t_summary/summary.html +9 -0
- data/t/t.rb +27 -0
- data/t/test_bike.rb +768 -0
- data/t/test_call.rb +1281 -0
- data/t/test_checkbox.rb +273 -0
- data/t/test_field.rb +330 -0
- data/t/test_file.rb +900 -0
- data/t/test_i18n.rb +325 -0
- data/t/test_id.rb +215 -0
- data/t/test_img.rb +328 -0
- data/t/test_meta.rb +57 -0
- data/t/test_parser.rb +1516 -0
- data/t/test_password.rb +188 -0
- data/t/test_radio.rb +226 -0
- data/t/test_role.rb +249 -0
- data/t/test_select.rb +182 -0
- data/t/test_set_complex.rb +527 -0
- data/t/test_set_dynamic.rb +1504 -0
- data/t/test_set_folder.rb +515 -0
- data/t/test_set_permit.rb +246 -0
- data/t/test_set_static.rb +468 -0
- data/t/test_storage.rb +915 -0
- data/t/test_text.rb +125 -0
- data/t/test_textarea.rb +138 -0
- data/t/test_timestamp.rb +473 -0
- data/t/test_workflow.rb +367 -0
- metadata +347 -0
data/lib/meta/_meta.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
module Bike::Meta
|
|
7
|
+
|
|
8
|
+
def post(action, v = nil)
|
|
9
|
+
super
|
|
10
|
+
my[:parent][klass_id] = val if my[:parent]
|
|
11
|
+
self
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def klass_id
|
|
17
|
+
self.class.to_s[/\w+$/].downcase.intern
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|
data/lib/meta/group.rb
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
class Bike::Meta::Group < Bike::Field
|
|
7
|
+
|
|
8
|
+
include Bike::Meta
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def _post(action, v)
|
|
13
|
+
if action == :load
|
|
14
|
+
@val = val_cast v
|
|
15
|
+
end
|
|
16
|
+
nil
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
data/lib/meta/id.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009-2010 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
class Bike::Meta::Id < Bike::Field
|
|
7
|
+
|
|
8
|
+
# not include Bike::Meta as this is SHORT_ID, not a full id.
|
|
9
|
+
|
|
10
|
+
def initialize(meta = {})
|
|
11
|
+
meta[:size] = $&.to_i if meta[:tokens] && meta[:tokens].first =~ /^\d+$/
|
|
12
|
+
super
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def errors
|
|
16
|
+
if (my[:max].to_i > 0) && (val.size > my[:max])
|
|
17
|
+
[_('too long: %{max} characters maximum') % {:max => my[:max]}]
|
|
18
|
+
elsif (my[:min].to_i == 1) && val.empty?
|
|
19
|
+
[_('mandatory')]
|
|
20
|
+
elsif (my[:min].to_i > 0) && (val.size < my[:min])
|
|
21
|
+
[_('too short: %{min} characters minimum') % {:min => my[:min]}]
|
|
22
|
+
elsif val !~ /\A#{Bike::REX::ID_SHORT}\z/
|
|
23
|
+
[_('malformatted id')]
|
|
24
|
+
elsif (
|
|
25
|
+
my[:parent] &&
|
|
26
|
+
my[:parent][:id] !~ /00000000_#{val}$/ &&
|
|
27
|
+
my[:parent][:parent].is_a?(Bike::Set::Dynamic) &&
|
|
28
|
+
my[:parent][:parent].item(val)
|
|
29
|
+
)
|
|
30
|
+
[_('duplicate id: %{id}') % {:id => val}]
|
|
31
|
+
else
|
|
32
|
+
[]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
private
|
|
37
|
+
|
|
38
|
+
def _g_create(arg)
|
|
39
|
+
new_id? ? <<_html.chomp : _g_default(arg)
|
|
40
|
+
<span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="#{Bike::Field.h val}" size="#{my[:size]}" />#{_g_errors arg}</span>
|
|
41
|
+
_html
|
|
42
|
+
end
|
|
43
|
+
alias :_g_update :_g_create
|
|
44
|
+
|
|
45
|
+
def new_id?
|
|
46
|
+
find_ancestor {|i| i[:id] =~ Bike::REX::ID_NEW } ? true : false
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def _post(action, v)
|
|
50
|
+
if action == :load || ([:create, :update].include?(action) && new_id?)
|
|
51
|
+
@val = val_cast v
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def val_cast(v)
|
|
56
|
+
v.to_s
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
data/lib/meta/owner.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
class Bike::Meta::Owner < Bike::Field
|
|
7
|
+
|
|
8
|
+
include Bike::Meta
|
|
9
|
+
|
|
10
|
+
private
|
|
11
|
+
|
|
12
|
+
def _post(action, v)
|
|
13
|
+
if action == :load
|
|
14
|
+
@val = val_cast v
|
|
15
|
+
elsif action == :create
|
|
16
|
+
@val = Bike.client
|
|
17
|
+
end
|
|
18
|
+
nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
require 'time'
|
|
7
|
+
|
|
8
|
+
class Bike::Meta::Timestamp < Bike::Field
|
|
9
|
+
|
|
10
|
+
include Bike::Meta
|
|
11
|
+
|
|
12
|
+
REX_DATE = /\A(\d+).(\d+).(\d+)(?:[T\s](\d+):(\d+)(?::(\d+))?)?\z/
|
|
13
|
+
|
|
14
|
+
def initialize(meta = {})
|
|
15
|
+
meta[:size] = $&.to_i if meta[:tokens] && meta[:tokens].find {|t| t =~ /^\d+$/ }
|
|
16
|
+
meta[:can_edit] = true if Array(meta[:tokens]).include? 'can_edit'
|
|
17
|
+
meta[:can_update] = true if Array(meta[:tokens]).include? 'can_update'
|
|
18
|
+
super
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def errors
|
|
22
|
+
if @date_str.nil?
|
|
23
|
+
[]
|
|
24
|
+
elsif @date_str =~ REX_DATE
|
|
25
|
+
(Time.local($1, $2, $3, $4, $5, $6) rescue nil) ? [] : ['out of range']
|
|
26
|
+
else
|
|
27
|
+
['wrong format']
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def _g_default(arg)
|
|
34
|
+
_date val['published']
|
|
35
|
+
end
|
|
36
|
+
alias :_g_published :_g_default
|
|
37
|
+
|
|
38
|
+
def _g_rfc2822(arg)
|
|
39
|
+
val['published'].rfc2822
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def _g_created(arg)
|
|
43
|
+
_date val['created']
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def _g_updated(arg)
|
|
47
|
+
_date val['updated']
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def _date(time)
|
|
51
|
+
time.is_a?(::Time) ? time.strftime(_('%Y-%m-%dT%H:%M:%S')) : 'n/a'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def _g_create(arg)
|
|
55
|
+
<<_html.chomp if my[:can_edit]
|
|
56
|
+
<span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="" size="#{my[:size]}" /></span>
|
|
57
|
+
_html
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def _g_update(arg)
|
|
61
|
+
if my[:can_edit]
|
|
62
|
+
v = @date_str
|
|
63
|
+
v ||= val['published'].is_a?(::Time) ? val['published'].strftime('%Y-%m-%d %H:%M:%S') : ''
|
|
64
|
+
<<_html.chomp
|
|
65
|
+
<span class="#{_g_class arg}"><input type="text" name="#{my[:short_name]}" value="#{Bike::Field.h v}" size="#{my[:size]}" />#{_g_errors arg}</span>
|
|
66
|
+
_html
|
|
67
|
+
elsif my[:can_update] && !find_ancestor {|f| f[:id] =~ Bike::REX::ID_NEW }
|
|
68
|
+
<<_html
|
|
69
|
+
<span class="#{_g_class arg}">
|
|
70
|
+
<input type="checkbox" id="timestamp_#{my[:short_name]}" name="#{my[:short_name]}" value="true" />
|
|
71
|
+
<label for="timestamp_#{my[:short_name]}">#{_ 'update the timestamp'}</label>
|
|
72
|
+
#{_g_errors arg}</span>
|
|
73
|
+
_html
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def _post(action, v)
|
|
78
|
+
case action
|
|
79
|
+
when :load
|
|
80
|
+
@val = val_cast v
|
|
81
|
+
when :create
|
|
82
|
+
now = Time.now
|
|
83
|
+
@val = {
|
|
84
|
+
'created' => now,
|
|
85
|
+
'updated' => now,
|
|
86
|
+
'published' => now,
|
|
87
|
+
}
|
|
88
|
+
if my[:can_edit] && v['published'].is_a?(::Time)
|
|
89
|
+
@val['published'] = v['published']
|
|
90
|
+
else
|
|
91
|
+
nil # do not set @action
|
|
92
|
+
end
|
|
93
|
+
when :update
|
|
94
|
+
@val['updated'] = Time.now
|
|
95
|
+
if my[:can_edit] && v['published'].is_a?(::Time)
|
|
96
|
+
@val['published'] = v['published']
|
|
97
|
+
elsif my[:can_update] && v['published'] == :same_as_updated
|
|
98
|
+
@val['published'] = @val['updated']
|
|
99
|
+
else
|
|
100
|
+
nil # do not set @action
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def val_cast(v)
|
|
106
|
+
if v.is_a? ::Hash
|
|
107
|
+
v
|
|
108
|
+
elsif v == 'true'
|
|
109
|
+
{'published' => :same_as_updated}
|
|
110
|
+
elsif v.is_a?(::String) && !v.empty?
|
|
111
|
+
@date_str = v
|
|
112
|
+
(v =~ REX_DATE && t = (Time.local($1, $2, $3, $4, $5, $6) rescue nil)) ? {'published' => t} : {}
|
|
113
|
+
else
|
|
114
|
+
{}
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
class Bike::Checkbox < Bike::Field
|
|
7
|
+
|
|
8
|
+
def initialize(meta = {})
|
|
9
|
+
if meta[:tokens]
|
|
10
|
+
meta[:options] ||= meta[:tokens] - ['mandatory']
|
|
11
|
+
meta[:options] = ['_on'] if meta[:options].empty?
|
|
12
|
+
meta[:mandatory] = meta[:tokens].include?('mandatory') && Array(meta[:options]).size > 1
|
|
13
|
+
end
|
|
14
|
+
if meta[:options].size == 1 && meta[:default] =~ /^(on|true|yes)$/i
|
|
15
|
+
meta[:default] = meta[:options].first
|
|
16
|
+
end
|
|
17
|
+
super
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def errors
|
|
21
|
+
if val.empty?
|
|
22
|
+
my[:mandatory] ? [_('mandatory')] : []
|
|
23
|
+
else
|
|
24
|
+
(val - my[:options]).empty? ? [] : [_('no such option')]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def _g_default(arg)
|
|
31
|
+
val.join ', '
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def _g_update(arg)
|
|
35
|
+
if my[:options] == ['_on']
|
|
36
|
+
checked = (val.include? '_on') ? ' checked' : ''
|
|
37
|
+
<<_html
|
|
38
|
+
<span class="#{_g_class arg}">
|
|
39
|
+
<input type="hidden" name="#{my[:short_name]}[]" value="" />
|
|
40
|
+
<input type="checkbox" name="#{my[:short_name]}[]" value="_on" #{checked}/>
|
|
41
|
+
#{_g_errors arg}</span>
|
|
42
|
+
_html
|
|
43
|
+
else
|
|
44
|
+
options = my[:options].collect {|opt|
|
|
45
|
+
checked = (val.include? opt) ? ' checked' : ''
|
|
46
|
+
<<_html
|
|
47
|
+
<span class="item">
|
|
48
|
+
<input type="checkbox" id="checkbox_#{my[:short_name]}-#{opt}" name="#{my[:short_name]}[]" value="#{opt}"#{checked} />
|
|
49
|
+
<label for="checkbox_#{my[:short_name]}-#{opt}">#{opt}</label>
|
|
50
|
+
</span>
|
|
51
|
+
_html
|
|
52
|
+
}.join
|
|
53
|
+
<<_html
|
|
54
|
+
<span class="#{_g_class arg}">
|
|
55
|
+
<input type="hidden" name="#{my[:short_name]}[]" value="" />
|
|
56
|
+
#{options}#{_g_errors arg}</span>
|
|
57
|
+
_html
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
alias :_g_create :_g_update
|
|
61
|
+
|
|
62
|
+
def val_cast(v)
|
|
63
|
+
Array(v).collect {|i|
|
|
64
|
+
i.to_s unless i.to_s.empty?
|
|
65
|
+
}.compact
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
end
|
data/lib/scalar/file.rb
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
|
|
3
|
+
# Author:: Akira FUNAI
|
|
4
|
+
# Copyright:: Copyright (c) 2009 Akira FUNAI
|
|
5
|
+
|
|
6
|
+
class Bike::File < Bike::Field
|
|
7
|
+
|
|
8
|
+
def initialize(meta = {})
|
|
9
|
+
meta[:options].collect! {|i| i.downcase } if meta[:options]
|
|
10
|
+
meta[:size] = $&.to_i if meta[:tokens] && meta[:tokens].first =~ /^\d+$/
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def meta_path
|
|
15
|
+
my[:full_name].gsub('-', '/')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def meta_tmp_path
|
|
19
|
+
"#{Bike.base[:path]}/#{Bike.base[:tid]}/#{my[:short_name].gsub('-', '/')}" if Bike.base
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def meta_persistent_sd
|
|
23
|
+
find_ancestor {|f| f.is_a?(Bike::Set::Dynamic) && f.storage.persistent? }
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def meta_persistent_name
|
|
27
|
+
f = my[:parent]
|
|
28
|
+
ps = my[:persistent_sd]
|
|
29
|
+
name = my[:id]
|
|
30
|
+
until f == ps
|
|
31
|
+
name = "#{f[:id]}-#{name}"
|
|
32
|
+
f = f[:parent]
|
|
33
|
+
end
|
|
34
|
+
name
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def body
|
|
38
|
+
raise Bike::Error::Forbidden unless permit? :read
|
|
39
|
+
|
|
40
|
+
if ps = my[:persistent_sd]
|
|
41
|
+
@body ||= ps.storage.val my[:persistent_name]
|
|
42
|
+
end
|
|
43
|
+
@body
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def errors
|
|
47
|
+
if (
|
|
48
|
+
val['basename'] &&
|
|
49
|
+
my[:options].is_a?(::Array) &&
|
|
50
|
+
!my[:options].empty? &&
|
|
51
|
+
!my[:options].include?(val['basename'].to_s[/\.([\w\.]+)$/i, 1].downcase)
|
|
52
|
+
)
|
|
53
|
+
[_('wrong file type: should be %{types}') % {:types => my[:options].join('/')}]
|
|
54
|
+
elsif (my[:max].to_i > 0) && (val['size'].to_i > my[:max])
|
|
55
|
+
[_('too large: %{max} bytes maximum') % {:max => my[:max]}]
|
|
56
|
+
elsif (my[:min].to_i == 1) && val['size'].to_i < 1
|
|
57
|
+
[_('mandatory')]
|
|
58
|
+
elsif (my[:min].to_i > 0) && (val['size'].to_i < my[:min])
|
|
59
|
+
[_('too small: %{min} bytes minimum') % {:min => my[:min]}]
|
|
60
|
+
else
|
|
61
|
+
[]
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def commit(type = :temp)
|
|
66
|
+
if type == :temp && @action == :delete
|
|
67
|
+
@val = {}
|
|
68
|
+
@body = nil
|
|
69
|
+
elsif type == :persistent && ps = my[:persistent_sd]
|
|
70
|
+
case @action
|
|
71
|
+
when :create, :update, nil
|
|
72
|
+
ps.storage.store(
|
|
73
|
+
my[:persistent_name],
|
|
74
|
+
@body,
|
|
75
|
+
val['basename'][/\.([\w\.]+)$/, 1] || 'bin'
|
|
76
|
+
) if @body && valid?
|
|
77
|
+
when :delete
|
|
78
|
+
ps.storage.delete my[:persistent_name]
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
super
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def _g_default(arg = {})
|
|
87
|
+
path = _path arg[:action]
|
|
88
|
+
basename = Bike::Field.h val['basename']
|
|
89
|
+
type = Bike::Field.h val['type']
|
|
90
|
+
<<_html.chomp unless val.empty?
|
|
91
|
+
<a href="#{path}/#{basename}">#{basename} (#{val['size']} bytes)</a>
|
|
92
|
+
_html
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def _g_update(arg)
|
|
96
|
+
hidden = <<_html if my[:min].to_i > 0 && val.empty?
|
|
97
|
+
<input type="hidden" name="#{my[:short_name]}" value="" />
|
|
98
|
+
_html
|
|
99
|
+
if (
|
|
100
|
+
!val.empty? &&
|
|
101
|
+
my[:min].to_i == 0 &&
|
|
102
|
+
my[:parent].is_a?(Bike::Set::Static) &&
|
|
103
|
+
my[:parent][:item].find {|id, meta| id != my[:id] && meta[:klass] !~ /^meta-/ }
|
|
104
|
+
)
|
|
105
|
+
delete = <<_html
|
|
106
|
+
<input type="submit" name="#{my[:short_name]}.action-delete" value="#{_ 'delete'}" />
|
|
107
|
+
_html
|
|
108
|
+
end
|
|
109
|
+
update = <<_html
|
|
110
|
+
<input type="file" name="#{my[:short_name]}" size="#{my[:size]}" class="file" />
|
|
111
|
+
_html
|
|
112
|
+
<<_html
|
|
113
|
+
<span class="#{_g_class arg}">
|
|
114
|
+
#{_g_default arg}
|
|
115
|
+
#{hidden}#{update}#{delete}#{_g_errors arg}</span>
|
|
116
|
+
_html
|
|
117
|
+
end
|
|
118
|
+
alias :_g_create :_g_update
|
|
119
|
+
|
|
120
|
+
def _path(action)
|
|
121
|
+
Bike.uri.to_s + ([:read, nil].include?(action) ? my[:path] : my[:tmp_path])
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def val_cast(v)
|
|
125
|
+
if v.is_a?(::Hash) && v[:tempfile]
|
|
126
|
+
v[:tempfile].rewind
|
|
127
|
+
@body = v[:tempfile].read
|
|
128
|
+
{
|
|
129
|
+
'basename' => File.basename(v[:filename]),
|
|
130
|
+
'type' => v[:type] || 'application/octet-stream',
|
|
131
|
+
'size' => @body.respond_to?(:bytesize) ? @body.bytesize : @body.size,
|
|
132
|
+
}
|
|
133
|
+
elsif v.is_a?(::Hash) && v['basename']
|
|
134
|
+
{
|
|
135
|
+
'basename' => v['basename'].to_s,
|
|
136
|
+
'type' => v['type'].to_s,
|
|
137
|
+
'size' => v['size'].to_i,
|
|
138
|
+
}
|
|
139
|
+
else
|
|
140
|
+
{}
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
end
|