card 1.16.14 → 1.16.15

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
  4. data/lib/card/auth.rb +15 -10
  5. data/lib/card/codename.rb +25 -21
  6. data/lib/card/content.rb +100 -68
  7. data/lib/card/format.rb +158 -129
  8. data/lib/card/query.rb +15 -9
  9. data/lib/card/query/attributes.rb +41 -49
  10. data/lib/card/set.rb +15 -12
  11. data/lib/card/set_pattern.rb +4 -5
  12. data/lib/card/spec_helper.rb +54 -16
  13. data/lib/cardio.rb +43 -25
  14. data/mod/01_core/chunk/include.rb +1 -1
  15. data/mod/01_core/set/all/collection.rb +76 -73
  16. data/mod/01_core/set/all/content.rb +0 -4
  17. data/mod/01_core/set/all/fetch.rb +35 -42
  18. data/mod/01_core/set/all/name.rb +17 -7
  19. data/mod/01_core/set/all/pattern.rb +12 -11
  20. data/mod/01_core/set/all/permissions.rb +51 -42
  21. data/mod/01_core/set/all/phases.rb +2 -1
  22. data/mod/01_core/set/all/references.rb +2 -2
  23. data/mod/01_core/set/all/rules.rb +28 -35
  24. data/mod/01_core/set/all/subcards.rb +12 -12
  25. data/mod/01_core/set/all/tracked_attributes.rb +1 -1
  26. data/mod/01_core/set/all/type.rb +11 -11
  27. data/mod/01_core/set/all/utils.rb +6 -1
  28. data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
  29. data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
  30. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
  31. data/mod/01_history/lib/card/action.rb +52 -47
  32. data/mod/01_history/set/all/actions.rb +20 -16
  33. data/mod/01_history/set/all/history.rb +18 -13
  34. data/mod/02_basic_types/set/all/base.rb +23 -2
  35. data/mod/02_basic_types/set/type/pointer.rb +45 -36
  36. data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
  37. data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
  38. data/mod/03_machines/set/right/machine_output.rb +10 -6
  39. data/mod/04_settings/set/abstract/permission.rb +10 -5
  40. data/mod/04_settings/set/type/setting.rb +4 -1
  41. data/mod/05_email/set/all/follow.rb +39 -44
  42. data/mod/05_email/set/all/notify.rb +4 -1
  43. data/mod/05_email/set/right/followers.rb +16 -14
  44. data/mod/05_email/set/self/follow_defaults.rb +22 -19
  45. data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
  46. data/mod/05_standard/set/abstract/attachment.rb +85 -58
  47. data/mod/05_standard/set/all/comment.rb +35 -19
  48. data/mod/05_standard/set/all/error.rb +124 -98
  49. data/mod/05_standard/set/all/list_changes.rb +27 -22
  50. data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
  51. data/mod/05_standard/set/all/rich_html/form.rb +123 -81
  52. data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
  53. data/mod/05_standard/set/right/account.rb +2 -2
  54. data/mod/05_standard/set/right/email.rb +3 -2
  55. data/mod/05_standard/set/rstar/rules.rb +3 -3
  56. data/mod/05_standard/set/self/search.rb +45 -22
  57. data/mod/05_standard/set/type/cardtype.rb +13 -11
  58. data/mod/05_standard/set/type/listed_by.rb +3 -2
  59. data/mod/05_standard/set/type/set.rb +17 -13
  60. data/mod/05_standard/set/type/signup.rb +1 -2
  61. data/mod/05_standard/set/type/user.rb +1 -1
  62. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  63. data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
  64. data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
  65. data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
  66. data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
  67. data/spec/models/card/trash_spec.rb +1 -1
  68. data/spec/spec_helper.rb +0 -1
  69. metadata +2 -2
@@ -2,26 +2,29 @@ format :html do
2
2
  def edit_slot args={}
3
3
  # note: @mode should already be :edit here...
4
4
  if args[:structure] || card.structure
5
- # multi-card editing
6
-
7
- if args[:core_edit] #need better name
8
- _render_core args
9
- else
10
- process_relative_tags optional_toolbar: :hide,
11
- structure: args[:structure]
12
- end
5
+ multi_card_edit_slot args
6
+ else
7
+ single_card_edit_slot args
8
+ end
9
+ end
13
10
 
11
+ def multi_card_edit_slot args
12
+ if args[:core_edit] # need better name
13
+ _render_core args
14
14
  else
15
- # single-card edit mode
16
- field = content_field form, args
15
+ process_relative_tags optional_toolbar: :hide,
16
+ structure: args[:structure]
17
+ end
18
+ end
17
19
 
18
- if [args[:optional_type_formgroup], args[:optional_name_formgroup]]
19
- .member? :show
20
- # display content field in formgroup for consistency with other fields
21
- formgroup '', field, editor: :content
22
- else
23
- editor_wrap( :content ) { field }
24
- end
20
+ def single_card_edit_slot args
21
+ field = content_field form, args
22
+ if [args[:optional_type_formgroup], args[:optional_name_formgroup]]
23
+ .member? :show
24
+ # display content field in formgroup for consistency with other fields
25
+ formgroup '', field, editor: :content
26
+ else
27
+ editor_wrap(:content) { field }
25
28
  end
26
29
  end
27
30
 
@@ -44,8 +47,8 @@ format :html do
44
47
  form_for card, card_form_opts(action, opts) do |form|
45
48
  @form = form
46
49
  %{
47
- #{ hidden_tags hidden_args if hidden_args }
48
- #{ yield form }
50
+ #{hidden_tags hidden_args if hidden_args}
51
+ #{yield form}
49
52
  }
50
53
  end
51
54
  end
@@ -61,14 +64,9 @@ format :html do
61
64
  end
62
65
 
63
66
  def card_form_opts action, html={}
64
- url, action = case action
65
- when Symbol ; [ path(action: action) , action ]
66
- when Hash ; [ path(action) , action[:action] ]
67
- when String ; [ card_path(action) , nil ] #deprecated
68
- else ; raise Card::Error, "unsupported card_form action class: #{action.class}"
69
- end
67
+ url, action = url_from_action(action)
70
68
 
71
- klasses = Array.wrap( html[:class] )
69
+ klasses = Array.wrap(html[:class])
72
70
  klasses << 'card-form slotter'
73
71
  klasses << 'autosave' if action == :update
74
72
  html[:class] = klasses.join ' '
@@ -79,33 +77,51 @@ format :html do
79
77
  { url: url, remote: true, html: html }
80
78
  end
81
79
 
80
+ def url_from_action action
81
+ case action
82
+ when Symbol
83
+ [path(action: action), action]
84
+ when Hash
85
+ [path(action), action[:action]]
86
+ when String # deprecated
87
+ [card_path(action), nil]
88
+ else
89
+ raise Card::Error, "unsupported card_form action class: #{action.class}"
90
+ end
91
+ end
92
+
82
93
  def editor_wrap type=nil
83
- content_tag( :div, class: "editor#{ " #{type}-editor" if type }" ) { yield.html_safe }
94
+ html_class = 'editor'
95
+ html_class << " #{type}-editor" if type
96
+ content_tag(:div, class: html_class) { yield.html_safe }
84
97
  end
85
98
 
86
99
  def formgroup title, content, opts={}
87
- help_text =
88
- case opts[:help]
89
- when String ; _render_help help_class: 'help-block', help_text: opts[:help]
90
- when true ; _render_help help_class: 'help-block'
91
- else ; nil
92
- end
93
-
94
- div_args = { class: ['form-group', opts[:class]].compact*' ' }
95
- div_args[:card_id ] = card.id if card.real?
96
- div_args[:card_name] = h card.name if card.name.present?
97
-
98
- wrap_with :div, div_args do
100
+ wrap_with :div, formgroup_div_args(opts[:class]) do
99
101
  %{
100
- <label>#{ title }</label>
102
+ <label>#{title}</label>
101
103
  <div>
102
- #{ editor_wrap( opts[:editor] ) { content } }
103
- #{ help_text }
104
+ #{editor_wrap(opts[:editor]) { content }}
105
+ #{formgroup_help_text opts[:help]}
104
106
  </div>
105
107
  }
106
108
  end
107
109
  end
108
110
 
111
+ def formgroup_div_args html_class
112
+ div_args = { class: ['form-group', html_class].compact.join(' ') }
113
+ div_args[:card_id] = card.id if card.real?
114
+ div_args[:card_name] = h card.name if card.name.present?
115
+ div_args
116
+ end
117
+
118
+ def formgroup_help_text text=nil
119
+ case text
120
+ when String then _render_help help_class: 'help-block', help_text: text
121
+ when true then _render_help help_class: 'help-block'
122
+ end
123
+ end
124
+
109
125
  def hidden_tags hash, base=nil
110
126
  # convert hash into a collection of hidden tags
111
127
  result = ''
@@ -125,7 +141,7 @@ format :html do
125
141
  # FIELDSET VIEWS
126
142
 
127
143
  view :name_formgroup do |args|
128
- formgroup 'name', raw( name_field form ), editor: 'name', help: args[:help]
144
+ formgroup 'name', raw(name_field form), editor: 'name', help: args[:help]
129
145
  end
130
146
 
131
147
  view :type_formgroup do |args|
@@ -150,26 +166,29 @@ format :html do
150
166
  }
151
167
  end
152
168
 
153
-
154
169
  def name_field form=nil, options={}
155
170
  form ||= self.form
156
- text_field( :name, {
157
- value: card.name, #needed because otherwise gets wrong value if there are updates
171
+ text_field(:name, {
172
+ # needed because otherwise gets wrong value if there are updates
173
+ value: card.name,
158
174
  autocomplete: 'off'
159
175
  }.merge(options))
160
176
  end
161
177
 
162
178
  def type_field args={}
163
179
  typelist = Auth.createable_types
164
- current_type = unless args.delete :no_current_type
165
- unless card.new_card? || typelist.include?( card.type_name )
166
- # current type should be an option on existing cards, regardless of create perms
167
- typelist = (typelist << card.type_name).sort
180
+ current_type =
181
+ unless args.delete :no_current_type
182
+ if !card.new_card? && !typelist.include?(card.type_name)
183
+ # current type should be an option on existing cards,
184
+ # regardless of create perms
185
+ typelist.push(card.type_name).sort!
168
186
  end
169
- Card[ card ? card.type_id : Card.default_type_id ].name
187
+ card.type_name_or_default
170
188
  end
171
189
 
172
- options = options_from_collection_for_select typelist, :to_s, :to_s, current_type
190
+ options = options_from_collection_for_select typelist, :to_s, :to_s,
191
+ current_type
173
192
  template.select_tag 'card[type]', options, args
174
193
  end
175
194
 
@@ -177,34 +196,36 @@ format :html do
177
196
  @form = form
178
197
  @nested = options[:nested]
179
198
  card.last_action_id_before_edit = card.last_action_id
180
- revision_tracking = if card && !card.new_card? && !options[:skip_rev_id]
181
- hidden_field :last_action_id_before_edit, class: 'current_revision_id'
182
- #hidden_field_tag 'card[last_action_id_before_edit]', card.last_action_id, class: 'current_revision_id'
183
- end
199
+ revision_tracking =
200
+ if card && !card.new_card? && !options[:skip_rev_id]
201
+ hidden_field :last_action_id_before_edit, class: 'current_revision_id'
202
+ # hidden_field_tag 'card[last_action_id_before_edit]',
203
+ # card.last_action_id, class: 'current_revision_id'
204
+ end
184
205
  %{
185
- #{ revision_tracking
186
- }
187
- #{ _render_editor options }
206
+ #{revision_tracking}
207
+ #{_render_editor options}
188
208
  }
189
209
  end
190
210
 
211
+ # FIELD VIEWS
191
212
 
192
- # FIELD VIEWS
193
-
194
- view :editor do |args|
195
- text_area :content, rows: 3, class: 'tinymce-textarea card-content', id: unique_id
213
+ view :editor do |_args|
214
+ text_area :content, rows: 3, class: 'tinymce-textarea card-content',
215
+ id: unique_id
196
216
  end
197
217
 
198
218
  view :edit_in_form, perms: :update, tags: :unknown_ok do |args|
199
219
  eform = form_for_multi
200
-
201
- content = content_field eform, args.merge( nested: true )
220
+ content = content_field eform, args.merge(nested: true)
221
+ if card.new_card?
222
+ content += raw("\n #{ eform.hidden_field :type_id }")
223
+ end
202
224
  opts = { editor: 'content', help: true, class: 'card-editor' }
203
-
204
- content += raw( "\n #{ eform.hidden_field :type_id }" ) if card.new_card?
205
- opts[:class] += " RIGHT-#{ card.cardname.tag_name.safe_key }" if card.cardname.junction?
206
-
207
- formgroup fancy_title( args[:title] ), content, opts
225
+ if card.cardname.junction?
226
+ opts[:class] += " RIGHT-#{ card.cardname.tag_name.safe_key }"
227
+ end
228
+ formgroup fancy_title(args[:title]), content, opts
208
229
  end
209
230
 
210
231
  def process_relative_tags args
@@ -212,31 +233,52 @@ format :html do
212
233
  nested_card = fetch_nested_card chunk.options
213
234
  nest nested_card, chunk.options.reverse_merge(args)
214
235
  end.join "\n"
215
- # _render_raw(args).scan( /\{\{\s*\+[^\}]*\}\}/ ).map do |inc| #fixme - wrong place for regexp!
216
- # process_content( inc ).strip
217
- # end.join
218
236
  end
219
237
 
220
238
  # form helpers
221
239
 
222
- FIELD_HELPERS = %w{hidden_field color_field date_field datetime_field datetime_local_field
223
- email_field month_field number_field password_field phone_field
224
- range_field search_field telephone_field text_area text_field time_field
225
- url_field week_field file_field}
226
-
240
+ FIELD_HELPERS =
241
+ %w{
242
+ hidden_field color_field date_field datetime_field datetime_local_field
243
+ email_field month_field number_field password_field phone_field
244
+ range_field search_field telephone_field text_area text_field time_field
245
+ url_field week_field file_field
246
+ }
227
247
 
228
248
  FIELD_HELPERS.each do |method_name|
229
- define_method(method_name) do |name, options = {}|
249
+ define_method(method_name) do |name, options={}|
230
250
  form.send(method_name, name, options)
231
251
  end
232
252
  end
233
253
 
234
- def check_box method, options={}, checked_value = "1", unchecked_value = "0"
254
+ def check_box method, options={}, checked_value = '1', unchecked_value = '0'
235
255
  form.check_box method, options, checked_value, unchecked_value
236
256
  end
237
257
 
238
- def radio_button method, tag_value, options = {}
258
+ def radio_button method, tag_value, options={}
239
259
  form.radio_button method, tag_value, options
240
260
  end
241
261
 
262
+ def submit_button args={}
263
+ args.reverse_merge!(
264
+ situation: 'primary',
265
+ data: {}
266
+ )
267
+ text = args.delete(:text) || 'Submit'
268
+ args[:data][:disable_with] ||= args.delete(:disable_with) || 'Submitting'
269
+ button_tag text, args
270
+ end
271
+
272
+ # redirect to *previous if no :href is given
273
+ def cancel_button args={}
274
+ args.reverse_merge! type: 'button'
275
+ if args[:href]
276
+ add_class args, 'slotter'
277
+ else
278
+ add_class args, 'redirecter'
279
+ args[:href] = Card.path_setting('/*previous')
280
+ end
281
+ text = args.delete(:text) || 'Cancel'
282
+ button_tag text, args
283
+ end
242
284
  end
@@ -1,22 +1,15 @@
1
1
  format :html do
2
-
3
-
4
-
5
-
6
2
  view :modal_link do |args|
7
3
  path_opts = args[:path_opts] || {}
8
4
  path_opts.merge!(layout: :modal)
9
5
  html_args = args[:html_args] || {}
10
- #html_args.merge!('data-target'=>"#modal-#{card.cardname.safe_key}#{args[:modal_slot_id_postfix]}",
11
- html_args.merge!('data-target'=>"#modal-main-slot",
12
- 'data-toggle'=>'modal')
6
+ html_args.merge!('data-target' => '#modal-main-slot',
7
+ 'data-toggle' => 'modal')
13
8
  link_to(args[:text] || _render_title(args), path(path_opts), html_args)
14
9
  end
15
10
 
16
11
  view :modal_slot do |args|
17
- #wrap_with(:div, class: 'modal fade', role: 'dialog', id: "modal-#{card.cardname.safe_key}#{args[:modal_slot_id_postfix]}") do
18
- id = "modal-"
19
- id += (args[:modal_id] || 'main-slot')
12
+ id = "modal-#{args[:modal_id] || 'main-slot'}"
20
13
  wrap_with(:div, class: 'modal fade', role: 'dialog', id: id) do
21
14
  wrap_with(:div, class: 'modal-dialog') do
22
15
  content_tag :div, class: 'modal-content' do
@@ -26,16 +19,19 @@ format :html do
26
19
  end
27
20
  end
28
21
 
29
-
30
- view :modal_menu, tags: :unknown_ok do |args|
22
+ view :modal_menu, tags: :unknown_ok do
31
23
  popout_params = {}
32
24
  popout_params[:view] = params[:view] if params[:view]
33
- # we probably want to pass on a lot more params than just view, but not all of them
25
+ # we probably want to pass on a lot more params than just view,
26
+ # but not all of them
34
27
  # (eg we don't want layout, id, controller...)
35
28
  wrap_with :div, class: 'modal-menu' do
36
29
  [
37
- link_to( glyphicon('remove'), '', class: 'close-modal pull-right close', 'data-dismiss'=>'modal'),
38
- link_to( glyphicon('new-window'), popout_params, class: 'pop-out-modal pull-right close ' )
30
+ link_to(glyphicon('remove'), '',
31
+ class: 'close-modal pull-right close',
32
+ 'data-dismiss' => 'modal'),
33
+ link_to(glyphicon('new-window'), popout_params,
34
+ class: 'pop-out-modal pull-right close ')
39
35
  ]
40
36
  end
41
37
  end
@@ -45,48 +41,9 @@ format :html do
45
41
  end
46
42
 
47
43
  def default_modal_footer_args args
48
- args[:buttons] ||= button_tag 'Close', class: 'btn-xs close-modal pull-right', 'data-dismiss'=>'modal'
49
- end
50
-
51
- =begin
52
- def default_modal_content_args args
53
- args[:buttons] ||= button_tag 'Close', 'data-dismiss'=>'modal'
54
- end
55
-
56
- view :modal_link_and_dialog do |args|
57
- _render_modal_link(args) + _render_modal(args)
58
- end
59
-
60
-
61
-
62
- # use modal_content for ajax calls to fill a modal_slot with content
63
- view :modal_content do |args|
64
- output [
65
- wrap_with( :div, _render_modal_header(args), class: 'modal-header' ),
66
- wrap_with( :div, _render_modal_body(args), class: 'modal-body' ),
67
- wrap_with( :div, _render_modal_footer(args), class: 'modal-footer' ),
68
- ]
44
+ args[:buttons] ||=
45
+ button_tag 'Close',
46
+ class: 'btn-xs close-modal pull-right',
47
+ 'data-dismiss' => 'modal'
69
48
  end
70
-
71
- view :modal_header do |args|
72
- _render_modal_title(args)
73
- end
74
-
75
- view :modal_body do |args|
76
- _render_core(args)
77
- end
78
-
79
- view :modal_footer do |args|
80
- args[:buttons] || ''
81
- end
82
-
83
- view :modal_title do |args|
84
- "<h4>#{_render_title args.merge(title_class: 'modal-title')}</h4>"
85
- end
86
-
87
- view :modal do |args|
88
- _render_modal_slot args.merge(optional_modal_content: :show)
89
- end
90
- =end
91
-
92
49
  end
@@ -70,13 +70,13 @@ event :require_email, on: :create, after: :approve do
70
70
  errors.add :email, 'required' unless subfield(:email)
71
71
  end
72
72
 
73
- event :set_default_salt, on: :create, before: :process_subcards do
73
+ event :set_default_salt, on: :create, before: :approve_subcards do
74
74
  salt = Digest::SHA1.hexdigest "--#{Time.zone.now}--"
75
75
  Env[:salt] = salt # HACK!!! need viable mechanism to get this to password
76
76
  add_subfield :salt, content: salt
77
77
  end
78
78
 
79
- event :set_default_status, on: :create, before: :process_subcards do
79
+ event :set_default_status, on: :create, before: :approve_subcards do
80
80
  default_status = Auth.needs_setup? ? 'active' : 'pending'
81
81
  add_subfield :status, content: default_status
82
82
  end
@@ -21,9 +21,10 @@ end
21
21
  event :validate_unique_email, after: :validate_email, on: :save do
22
22
  if content.present?
23
23
  Auth.as_bot do
24
- wql = { right_id: Card::EmailID, eq: content }
24
+ wql = { right_id: Card::EmailID, eq: content, return: :id }
25
25
  wql[:not] = { id: id } if id
26
- if Card.search(wql).first
26
+ wql_comment = "email duplicate? (#{content})"
27
+ if Card.search(wql, wql_comment).first
27
28
  errors.add :content, 'must be unique'
28
29
  end
29
30
  end
@@ -146,9 +146,9 @@ format :html do
146
146
  args[:delete_button] ||= delete_button args
147
147
  args[:cancel_button] ||=
148
148
  begin
149
- cancel_path = path view: ( card.new_card? ? :closed_rule : :open_rule ), success: false
150
- button_tag( 'Cancel', class: 'rule-cancel-button slotter', type: 'button',
151
- href: cancel_path )
149
+ cancel_view = card.new_card? ? :closed_rule : :open_rule
150
+ cancel_button class: 'rule-cancel-button',
151
+ href: path(view: cancel_view, success: false)
152
152
  end
153
153
  end
154
154