bureaucrat 0.0.3 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,64 +1,92 @@
1
- require 'bureaucrat/fields'
2
-
3
1
  module Bureaucrat
4
- module Quickfields
5
- include Fields
6
-
7
- def hide(name)
8
- base_fields[name] = base_fields[name].dup
9
- base_fields[name].widget = Widgets::HiddenInput.new
10
- end
11
-
12
- def string(name, options={})
13
- field name, CharField.new(options)
14
- end
15
-
16
- def text(name, options={})
17
- field name, CharField.new(options.merge(:widget => Widgets::Textarea.new))
18
- end
19
-
20
- def password(name, options={})
21
- field name, CharField.new(options.merge(:widget => Widgets::PasswordInput.new))
2
+ # Shortcuts for declaring form fields
3
+ module Quickfields
4
+ include Fields
5
+
6
+ # Hide field named +name+
7
+ def hide(name)
8
+ base_fields[name] = base_fields[name].dup
9
+ base_fields[name].widget = Widgets::HiddenInput.new
10
+ end
11
+
12
+ # Delete field named +name+
13
+ def delete(name)
14
+ base_fields.delete name
15
+ end
16
+
17
+ # Declare a +CharField+ with text input widget
18
+ def string(name, options = {})
19
+ field name, CharField.new(options)
20
+ end
21
+
22
+ # Declare a +CharField+ with text area widget
23
+ def text(name, options = {})
24
+ field name, CharField.new(options.merge(widget: Widgets::Textarea.new))
25
+ end
26
+
27
+ # Declare a +CharField+ with password widget
28
+ def password(name, options = {})
29
+ field name, CharField.new(options.merge(widget: Widgets::PasswordInput.new))
30
+ end
31
+
32
+ # Declare an +IntegerField+
33
+ def integer(name, options = {})
34
+ field name, IntegerField.new(options)
35
+ end
36
+
37
+ # Declare a +BigDecimalField+
38
+ def decimal(name, options = {})
39
+ field name, BigDecimalField.new(options)
40
+ end
41
+
42
+ # Declare a +RegexField+
43
+ def regex(name, regexp, options = {})
44
+ field name, RegexField.new(regexp, options)
45
+ end
46
+
47
+ # Declare an +EmailField+
48
+ def email(name, options = {})
49
+ field name, EmailField.new(options)
50
+ end
51
+
52
+ # Declare a +FileField+
53
+ def file(name, options = {})
54
+ field name, FileField.new(options)
55
+ end
56
+
57
+ # Declare a +BooleanField+
58
+ def boolean(name, options = {})
59
+ field name, BooleanField.new(options)
60
+ end
61
+
62
+ # Declare a +NullBooleanField+
63
+ def null_boolean(name, options = {})
64
+ field name, NullBooleanField.new(options)
65
+ end
66
+
67
+ # Declare a +ChoiceField+ with +choices+
68
+ def choice(name, choices = [], options = {})
69
+ field name, ChoiceField.new(choices, options)
70
+ end
71
+
72
+ # Declare a +TypedChoiceField+ with +choices+
73
+ def typed_choice(name, choices = [], options = {})
74
+ field name, TypedChoiceField.new(choices, options)
75
+ end
76
+
77
+ # Declare a +MultipleChoiceField+ with +choices+
78
+ def multiple_choice(name, choices = [], options = {})
79
+ field name, MultipleChoiceField.new(choices, options)
80
+ end
81
+
82
+ # Declare a +ChoiceField+ using the +RadioSelect+ widget
83
+ def radio_choice(name, choices = [], options = {})
84
+ field name, ChoiceField.new(choices, options.merge(widget: Widgets::RadioSelect.new))
85
+ end
86
+
87
+ # Declare a +MultipleChoiceField+ with the +CheckboxSelectMultiple+ widget
88
+ def checkbox_multiple_choice(name, choices = [], options = {})
89
+ field name, MultipleChoiceField.new(choices, options.merge(widget: Widgets::CheckboxSelectMultiple.new))
90
+ end
22
91
  end
23
-
24
- def integer(name, options={})
25
- field name, IntegerField.new(options)
26
- end
27
-
28
- def decimal(name, options={})
29
- field name, BigDecimalField.new(options)
30
- end
31
-
32
- def regex(name, regexp, options={})
33
- field name, RegexField.new(regexp, options)
34
- end
35
-
36
- def email(name, options={})
37
- field name, EmailField.new(options)
38
- end
39
-
40
- def file(name, options={})
41
- field name, FileField.new(options)
42
- end
43
-
44
- def boolean(name, options={})
45
- field name, BooleanField.new(options)
46
- end
47
-
48
- def null_boolean(name, options={})
49
- field name, NullBooleanField.new(options)
50
- end
51
-
52
- def choice(name, choices=[], options={})
53
- field name, ChoiceField.new(choices, options)
54
- end
55
-
56
- def typed_choice(name, choices=[], options={})
57
- field name, TypedChoiceField.new(choices, options)
58
- end
59
-
60
- def multiple_choice(name, choices=[], options={})
61
- field name, MultipleChoiceField.new(choices, options)
62
- end
63
-
64
- end; end
92
+ end
@@ -0,0 +1,14 @@
1
+ module Bureaucrat
2
+ class TemporaryUploadedFile
3
+ attr_accessor :filename, :content_type, :name, :tempfile, :head
4
+
5
+ def initialize(data)
6
+ @filename = data[:filename]
7
+ @content_type = data[:content_type]
8
+ @name = data[:name]
9
+ @tempfile = data[:tempfile]
10
+ @size = @tempfile.size
11
+ @head = data[:head]
12
+ end
13
+ end
14
+ end
@@ -1,84 +1,101 @@
1
1
  module Bureaucrat
2
- module Utils
2
+ module Utils
3
+ extend self
3
4
 
4
- module SafeData
5
- end
5
+ module SafeData
6
+ end
6
7
 
7
- class SafeString < String
8
- include SafeData
8
+ class SafeString < String
9
+ include SafeData
9
10
 
10
- def +(rhs)
11
- rhs.is_a?(SafeString) ? SafeString.new(super(rhs)) : super(rhs)
11
+ def +(rhs)
12
+ rhs.is_a?(SafeString) ? SafeString.new(super(rhs)) : super(rhs)
13
+ end
12
14
  end
13
- end
14
15
 
15
- # Dumb implementation that is good enough for Forms
16
- class OrderedHash < Hash
17
- def initialize
18
- super()
19
- @ordered_keys = []
20
- end
16
+ class StringAccessHash < Hash
17
+ def initialize(other = {})
18
+ super()
19
+ update(other)
20
+ end
21
21
 
22
- def []=(key, value)
23
- super(key, value)
24
- @ordered_keys << key unless @ordered_keys.include?(key)
25
- end
22
+ def []=(key, value)
23
+ super(key.to_s, value)
24
+ end
26
25
 
27
- def each
28
- @ordered_keys.each do |key|
29
- yield key, self[key]
30
- end
31
- end
26
+ def [](key)
27
+ super(key.to_s)
28
+ end
32
29
 
33
- def initialize_copy(original)
34
- super(original)
35
- @ordered_keys = original.instance_eval('@ordered_keys').dup
30
+ def fetch(key, *args)
31
+ super(key.to_s, *args)
32
+ end
33
+
34
+ def include?(key)
35
+ super(key.to_s)
36
+ end
37
+
38
+ def update(other)
39
+ other.each_pair{|k, v| self[k] = v}
40
+ self
41
+ end
42
+
43
+ def merge(other)
44
+ dup.update(other)
45
+ end
46
+
47
+ def delete(key)
48
+ super(key.to_s)
49
+ end
36
50
  end
37
- end
38
51
 
39
- module_function
52
+ def blank_value?(value)
53
+ !value || value == ''
54
+ end
40
55
 
41
- def mark_safe(s)
42
- s.is_a?(SafeData) ? s : SafeString.new(s.to_s)
43
- end
56
+ def mark_safe(s)
57
+ s.is_a?(SafeData) ? s : SafeString.new(s.to_s)
58
+ end
44
59
 
45
- ESCAPES = {
46
- '&' => '&amp;',
47
- '<' => '&lt;',
48
- '>' => '&gt;',
49
- '"' => '&quot;',
50
- "'" => '&#39;'
51
- }
52
- def escape(html)
53
- mark_safe(html.gsub(/[&<>"']/) {|match| ESCAPES[match]})
54
- end
60
+ ESCAPES = {
61
+ '&' => '&amp;',
62
+ '<' => '&lt;',
63
+ '>' => '&gt;',
64
+ '"' => '&quot;',
65
+ "'" => '&#39;'
66
+ }
67
+ def escape(html)
68
+ mark_safe(html.gsub(/[&<>"']/) {|match| ESCAPES[match]})
69
+ end
55
70
 
56
- def conditional_escape(html)
57
- html.is_a?(SafeData) ? html : escape(html)
58
- end
71
+ def conditional_escape(html)
72
+ html.is_a?(SafeData) ? html : escape(html)
73
+ end
59
74
 
60
- def flatatt(attrs)
61
- attrs.map {|k, v| " #{k}=\"#{conditional_escape(v)}\""}.join('')
62
- end
75
+ def flatatt(attrs)
76
+ attrs.map {|k, v| " #{k}=\"#{conditional_escape(v)}\""}.join('')
77
+ end
63
78
 
64
- def format_string(string, values)
65
- output = string.dup
66
- values.each_pair do |variable, value|
79
+ def format_string(string, values)
80
+ output = string.dup
81
+ values.each_pair do |variable, value|
67
82
  output.gsub!(/%\(#{variable}\)s/, value.to_s)
68
83
  end
69
- output
70
- end
84
+ output
85
+ end
71
86
 
72
- def pretty_name(name)
73
- name.to_s.capitalize.gsub(/_/, ' ')
74
- end
87
+ def pretty_name(name)
88
+ name.to_s.capitalize.gsub(/_/, ' ')
89
+ end
75
90
 
76
- def make_float(value)
77
- value += '0' if value.is_a?(String) && value != '.' && value[-1,1] == '.'
78
- Float(value)
79
- end
91
+ def make_float(value)
92
+ value += '0' if value.is_a?(String) && value != '.' && value[-1,1] == '.'
93
+ Float(value)
94
+ end
95
+
96
+ def make_bool(value)
97
+ !(value.respond_to?(:empty?) ? value.empty? : [0, nil, false].include?(value))
98
+ end
80
99
 
81
- def make_bool(value)
82
- !(value.respond_to?(:empty?) ? value.empty? : [0, nil, false].include?(value))
83
100
  end
84
- end; end
101
+ end
@@ -0,0 +1,163 @@
1
+ module Bureaucrat
2
+ module Validators
3
+ def empty_value?(value)
4
+ value.nil? || value == '' || value == [] || value == {}
5
+ end
6
+ module_function :empty_value?
7
+
8
+ class RegexValidator
9
+ attr_accessor :regex, :message, :code
10
+
11
+ def initialize(options = {})
12
+ @regex = Regexp.new(options.fetch(:regex, ''))
13
+ @message = options.fetch(:message, 'Enter a valid value.')
14
+ @code = options.fetch(:code, :invalid)
15
+ end
16
+
17
+ # Validates that the input validates the regular expression
18
+ def call(value)
19
+ if regex !~ value
20
+ raise ValidationError.new(@message, code, regex: regex)
21
+ end
22
+ end
23
+ end
24
+
25
+ ValidateInteger = lambda do |value|
26
+ begin
27
+ Integer(value)
28
+ rescue ArgumentError
29
+ raise ValidationError.new('')
30
+ end
31
+ end
32
+
33
+ # Original from Django's EmailField:
34
+ # email_re = re.compile(
35
+ # r"(^[-!#$%&'*+/=?^_`{}|~0-9A-Z]+(\.[-!#$%&'*+/=?^_`{}|~0-9A-Z]+)*" # dot-atom
36
+ # r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"' # quoted-string
37
+ # r')@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$', re.IGNORECASE) # domain
38
+ EMAIL_RE = /
39
+ (^[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+(\.[-!#\$%&'*+\/=?^_`{}|~0-9A-Z]+)*
40
+ |^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"
41
+ )@(?:[A-Z0-9]+(?:-*[A-Z0-9]+)*\.)+[A-Z]{2,6}$
42
+ /xi
43
+
44
+ ValidateEmail =
45
+ RegexValidator.new(regex: EMAIL_RE,
46
+ message: 'Enter a valid e-mail address.')
47
+
48
+ SLUG_RE = /^[-\w]+$/
49
+
50
+ ValidateSlug =
51
+ RegexValidator.new(regex: SLUG_RE,
52
+ message: "Enter a valid 'slug' consisting of letters, numbers, underscores or hyphens.")
53
+
54
+ IPV4_RE = /^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$/
55
+
56
+ IPV4Validator =
57
+ RegexValidator.new(regex: IPV4_RE,
58
+ message: 'Enter a valid IPv4 address.')
59
+
60
+ COMMA_SEPARATED_INT_LIST_RE = /^[\d,]+$/
61
+
62
+ ValidateCommaSeparatedIntegerList =
63
+ RegexValidator.new(regex: COMMA_SEPARATED_INT_LIST_RE,
64
+ message: 'Enter only digits separated by commas.',
65
+ code: :invalid)
66
+
67
+ class BaseValidator
68
+ def initialize(limit_value)
69
+ @limit_value = limit_value
70
+ end
71
+
72
+ def message
73
+ 'Ensure this value is %(limit_value)s (it is %(show_value)s).'
74
+ end
75
+
76
+ def code
77
+ :limit_value
78
+ end
79
+
80
+ def compare(a, b)
81
+ a.object_id != b.object_id
82
+ end
83
+
84
+ def clean(x)
85
+ x
86
+ end
87
+
88
+ def call(value)
89
+ cleaned = clean(value)
90
+ params = { limit_value: @limit_value, show_value: cleaned }
91
+
92
+ if compare(cleaned, @limit_value)
93
+ msg = Utils.format_string(message, params)
94
+ raise ValidationError.new(msg, code, params)
95
+ end
96
+ end
97
+ end
98
+
99
+ class MaxValueValidator < BaseValidator
100
+ def message
101
+ 'Ensure this value is less than or equal to %(limit_value)s.'
102
+ end
103
+
104
+ def code
105
+ :max_value
106
+ end
107
+
108
+ def compare(a, b)
109
+ a > b
110
+ end
111
+ end
112
+
113
+ class MinValueValidator < BaseValidator
114
+ def message
115
+ 'Ensure this value is greater than or equal to %(limit_value)s.'
116
+ end
117
+
118
+ def code
119
+ :min_value
120
+ end
121
+
122
+ def compare(a, b)
123
+ a < b
124
+ end
125
+ end
126
+
127
+ class MinLengthValidator < BaseValidator
128
+ def message
129
+ 'Ensure this value has at least %(limit_value)d characters (it has %(show_value)d).'
130
+ end
131
+
132
+ def code
133
+ :min_length
134
+ end
135
+
136
+ def compare(a, b)
137
+ a < b
138
+ end
139
+
140
+ def clean(x)
141
+ x.length
142
+ end
143
+ end
144
+
145
+ class MaxLengthValidator < BaseValidator
146
+ def message
147
+ 'Ensure this value has at most %(limit_value)d characters (it has %(show_value)d).'
148
+ end
149
+
150
+ def code
151
+ :max_length
152
+ end
153
+
154
+ def compare(a, b)
155
+ a > b
156
+ end
157
+
158
+ def clean(x)
159
+ x.length
160
+ end
161
+ end
162
+ end
163
+ end