card 1.16.8 → 1.16.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/{20150611203506_rails_inflection_updates.rb → 20120611203506_rails_inflection_updates.rb} +0 -0
  4. data/db/migrate_core_cards/20150326205655_bootswatch_themes.rb +0 -1
  5. data/db/migrate_core_cards/20150429090551_search_card_context.rb +1 -1
  6. data/db/migrate_core_cards/20150708224756_add_list_cards.rb +22 -0
  7. data/db/seed/new/card_actions.yml +789 -509
  8. data/db/seed/new/card_acts.yml +1 -1
  9. data/db/seed/new/card_changes.yml +2618 -1920
  10. data/db/seed/new/card_references.yml +1034 -901
  11. data/db/seed/new/cards.yml +2303 -1675
  12. data/db/seed/test/fixtures/card_actions.yml +1926 -1606
  13. data/db/seed/test/fixtures/card_acts.yml +354 -324
  14. data/db/seed/test/fixtures/card_changes.yml +5950 -5175
  15. data/db/seed/test/fixtures/card_references.yml +1861 -1630
  16. data/db/seed/test/fixtures/cards.yml +3768 -3048
  17. data/db/seed/test/seed.rb +121 -107
  18. data/lib/card.rb +2 -3
  19. data/lib/card/active_record_helper.rb +44 -0
  20. data/lib/card/auth.rb +51 -47
  21. data/lib/card/cache.rb +7 -3
  22. data/lib/card/codename.rb +7 -7
  23. data/lib/card/format.rb +2 -1
  24. data/lib/card/migration.rb +17 -16
  25. data/lib/card/name.rb +71 -20
  26. data/lib/card/set.rb +202 -166
  27. data/lib/card/simplecov_helper.rb +11 -7
  28. data/lib/card/subcards.rb +249 -0
  29. data/mod/01_core/set/all/collection.rb +1 -2
  30. data/mod/01_core/set/all/fetch.rb +167 -92
  31. data/mod/01_core/set/all/initialize.rb +8 -22
  32. data/mod/01_core/set/all/name.rb +128 -79
  33. data/mod/01_core/set/all/phases.rb +93 -95
  34. data/mod/01_core/set/all/subcards.rb +70 -0
  35. data/mod/01_core/set/all/tracked_attributes.rb +83 -59
  36. data/mod/01_core/set/all/trash.rb +14 -12
  37. data/mod/01_core/set/all/type.rb +3 -24
  38. data/mod/01_core/spec/set/all/initialize_spec.rb +44 -14
  39. data/mod/01_core/spec/set/all/permissions_spec.rb +206 -185
  40. data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +0 -10
  41. data/mod/01_core/spec/set/all/trash_spec.rb +38 -13
  42. data/mod/01_core/spec/set/all/type_spec.rb +0 -19
  43. data/mod/01_history/set/all/content_history.rb +5 -3
  44. data/mod/01_history/set/all/history.rb +117 -82
  45. data/mod/02_basic_types/set/all/base.rb +50 -49
  46. data/mod/03_machines/lib/card/machine.rb +2 -1
  47. data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +55 -17
  48. data/mod/03_machines/spec/set/type/javascript_spec.rb +18 -12
  49. data/mod/05_email/set/right/followers.rb +5 -5
  50. data/mod/05_email/set/right/following.rb +1 -1
  51. data/mod/05_email/set/type_plus_right/user/follow.rb +1 -1
  52. data/mod/05_standard/lib/carrier_wave/cardmount.rb +19 -11
  53. data/mod/05_standard/lib/file_uploader.rb +1 -1
  54. data/mod/05_standard/set/abstract/attachment.rb +20 -8
  55. data/mod/05_standard/set/all/list_changes.rb +43 -0
  56. data/mod/05_standard/set/all/rich_html/form.rb +21 -11
  57. data/mod/05_standard/set/all/rich_html/menu.rb +1 -1
  58. data/mod/05_standard/set/right/account.rb +5 -5
  59. data/mod/05_standard/set/self/head.rb +0 -1
  60. data/mod/05_standard/set/self/signin.rb +43 -35
  61. data/mod/05_standard/set/type/file.rb +9 -2
  62. data/mod/05_standard/set/type/list.rb +134 -0
  63. data/mod/05_standard/set/type/listed_by.rb +94 -0
  64. data/mod/05_standard/set/type/search_type.rb +62 -61
  65. data/mod/05_standard/set/type/signup.rb +94 -63
  66. data/mod/05_standard/set/type/user.rb +48 -39
  67. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  68. data/mod/05_standard/spec/set/all/rich_html/form_spec.rb +2 -2
  69. data/mod/05_standard/spec/set/self/signin_spec.rb +23 -27
  70. data/mod/05_standard/spec/set/type/email_template_spec.rb +0 -2
  71. data/mod/05_standard/spec/set/type/list_spec.rb +140 -0
  72. data/mod/05_standard/spec/set/type/listed_by_spec.rb +157 -0
  73. data/mod/05_standard/spec/set/type/signup_spec.rb +38 -32
  74. data/spec/lib/card/subcards_spec.rb +126 -0
  75. metadata +14 -3
@@ -1,7 +1,7 @@
1
1
  JUNK_INIT_ARGS = %w{ missing skip_virtual id }
2
2
 
3
3
  module ClassMethods
4
- def new args={}, options={}
4
+ def new args = {}, _options = {}
5
5
  args = (args || {}).stringify_keys
6
6
  JUNK_INIT_ARGS.each { |a| args.delete(a) }
7
7
  %w{ type type_code }.each { |k| args.delete(k) if args[k].blank? }
@@ -10,30 +10,17 @@ module ClassMethods
10
10
  end
11
11
  end
12
12
 
13
- def initialize args={}
14
- args['name'] = args['name' ].to_s
15
- args['type_id'] = args['type_id'].to_i
16
-
17
- args.delete('type_id') if args['type_id'] == 0 # can come in as 0, '', or nil
18
- @type_args = {
19
- type: args.delete('type' ),
20
- type_code: args.delete('type_code'),
21
- type_id: args[ 'type_id' ]
22
- }
23
-
13
+ def initialize args = {}
14
+ args['name'] = args['name'].to_s
24
15
  args['db_content'] = args.delete('content') if args['content']
25
-
26
- #FIXME -- too much of the above is duplicated by assign_attributes (tracked_attributes.rb)
27
-
28
16
  @supercard = args.delete 'supercard' # must come before name =
29
17
  skip_modules = args.delete 'skip_modules'
18
+ skip_type_lookup = args['skip_type_lookup']
30
19
 
31
20
  super args # ActiveRecord #initialize
32
-
33
- if tid = get_type_id( @type_args )
34
- self.type_id = tid
21
+ if !type_id && !skip_type_lookup
22
+ self.type_id = get_type_id_from_structure
35
23
  end
36
-
37
24
  include_set_modules unless skip_modules
38
25
  self
39
26
  end
@@ -44,12 +31,11 @@ def include_set_modules
44
31
  singleton_class.send :include, m
45
32
  end
46
33
  assign_set_specific_attributes
47
- @set_mods_loaded=true
34
+ @set_mods_loaded = true
48
35
  end
49
36
  self
50
37
  end
51
38
 
52
-
53
39
  event :initialize_success_object, before: :handle do
54
40
  Env[:success] = Success.new(cardname, Env.params[:success])
55
- end
41
+ end
@@ -1,24 +1,43 @@
1
1
  require 'uuid'
2
2
 
3
+ module ClassMethods
4
+ def uniquify_name name, rename=false
5
+ return name unless Card[name]
6
+ uniq_name = "#{name} 1"
7
+ while Card[uniq_name]
8
+ uniq_name.next!
9
+ end
10
+ return uniq_name unless rename
11
+
12
+ Card[name].update_attributes! name: uniq_name,
13
+ update_referencers: true
14
+ # name conflict resolved; original name can be used
15
+ name
16
+ end
17
+ end
18
+
3
19
  def name= newname
4
20
  cardname = newname.to_name
5
21
  if @supercard
6
- @relative_name = cardname.to_s
7
- relparts = @relative_name.to_name.parts
8
- @superleft = @supercard if relparts.size==2 && relparts.first.blank?
9
- cardname = @relative_name.to_name.to_absolute_name @supercard.name
22
+ @supercard.subcards.rename key, cardname.key
23
+ @contextual_name = cardname.to_s
24
+ relparts = cardname.parts
25
+ if relparts.size == 2 &&
26
+ (relparts.first.blank? || relparts.first.to_name.key == @supercard.key)
27
+ @superleft = @supercard
28
+ end
29
+ cardname = cardname.to_absolute_name @supercard.name
10
30
  end
11
31
 
12
32
  newkey = cardname.key
13
33
  if key != newkey
14
34
  self.key = newkey
15
- reset_patterns_if_rule # reset the old name - should be handled in tracked_attributes!!
35
+ # reset the old name - should be handled in tracked_attributes!!
36
+ reset_patterns_if_rule
16
37
  reset_patterns
17
38
  end
18
-
19
- subcards.each do |subkey, subcard|
20
- next unless Card===subcard
21
- subcard.name = subkey.to_name.to_absolute cardname
39
+ subcards.each do |subcard|
40
+ subcard.name = subcard.cardname.replace_part name, newname
22
41
  end
23
42
 
24
43
  write_attribute :name, cardname.s
@@ -45,49 +64,63 @@ def junction?
45
64
  cardname.junction?
46
65
  end
47
66
 
67
+ def contextual_name
68
+ @contextual_name || name
69
+ end
70
+
71
+ def relative_name context_name=nil
72
+ if !context_name && @supercard
73
+ context_name = @supercard.cardname
74
+ end
75
+ cardname.relative_name(context_name)
76
+ end
48
77
 
49
- def relative_name
50
- @relative_name || name
78
+ def absolute_name context_name=nil
79
+ if !context_name && @supercard
80
+ context_name = @supercard.cardname
81
+ end
82
+ cardname.absolute_name(context_name)
51
83
  end
52
84
 
53
85
  def left *args
54
- if !simple?
55
- @superleft or begin
56
- unless name_changed? and name.to_name.trunk_name.key == name_was.to_name.key
57
- # prevent recursion when, eg, renaming A+B to A+B+C
58
- Card.fetch cardname.left, *args
59
- end
86
+ return if simple?
87
+ @superleft || begin
88
+ unless name_changed? &&
89
+ name.to_name.trunk_name.key == name_was.to_name.key
90
+ # prevent recursion when, eg, renaming A+B to A+B+C
91
+ Card.fetch cardname.left, *args
60
92
  end
61
93
  end
62
94
  end
63
95
 
64
96
  def right *args
65
- Card.fetch( cardname.right, *args ) if !simple?
97
+ Card.fetch(cardname.right, *args) if !simple?
66
98
  end
67
99
 
68
100
  def [] *args
69
- if args[0].kind_of?(Fixnum) || args[0].kind_of?(Range)
101
+ case args[0]
102
+ when Fixnum, Range
70
103
  fetch_name = Array.wrap(cardname.parts[args[0]]).compact.join '+'
71
- Card.fetch( fetch_name, args[1] || {} ) if !simple?
104
+ Card.fetch(fetch_name, args[1] || {}) if !simple?
72
105
  else
73
106
  super
74
107
  end
75
108
  end
76
109
 
77
110
  def trunk *args
78
- simple? ? self : left( *args )
111
+ simple? ? self : left(*args)
79
112
  end
80
113
 
81
114
  def tag *args
82
- simple? ? self : Card.fetch( cardname.right, *args )
115
+ simple? ? self : Card.fetch(cardname.right, *args)
83
116
  end
84
117
 
85
118
  def left_or_new args={}
86
- left args or Card.new args.merge(name: cardname.left)
119
+ left(args) || Card.new(args.merge(name: cardname.left))
87
120
  end
88
121
 
89
122
  def children
90
- Card.search( { (simple? ? :part : :left) => name } ).to_a
123
+ Card.search((simple? ? :part : :left) => name).to_a
91
124
  end
92
125
 
93
126
  def dependents
@@ -101,7 +134,7 @@ def dependents
101
134
  array + card.dependents
102
135
  end
103
136
  end
104
- #Rails.logger.warn "dependents[#{inspect}] #{@dependents.inspect}"
137
+ # Rails.logger.warn "dependents[#{inspect}] #{@dependents.inspect}"
105
138
  end
106
139
  @dependents
107
140
  end
@@ -110,18 +143,18 @@ def repair_key
110
143
  Auth.as_bot do
111
144
  correct_key = cardname.key
112
145
  current_key = key
113
- return self if current_key==correct_key
146
+ return self if current_key == correct_key
114
147
 
115
- if key_blocker = Card.find_by_key_and_trash(correct_key, true)
148
+ if (key_blocker = Card.find_by_key_and_trash(correct_key, true))
116
149
  key_blocker.cardname = key_blocker.cardname + "*trash#{rand(4)}"
117
150
  key_blocker.save
118
151
  end
119
152
 
120
- saved = ( self.key = correct_key and self.save! )
121
- saved ||= ( self.cardname = current_key and self.save! )
153
+ saved = (self.key = correct_key) && self.save!
154
+ saved ||= (self.cardname = current_key) && self.save!
122
155
 
123
156
  if saved
124
- self.dependents.each { |c| c.repair_key }
157
+ dependents.each(&:repair_key)
125
158
  else
126
159
  Rails.logger.debug "FAILED TO REPAIR BROKEN KEY: #{key}"
127
160
  self.name = "BROKEN KEY: #{name}"
@@ -133,13 +166,13 @@ rescue
133
166
  self
134
167
  end
135
168
 
136
-
137
169
  event :permit_codename, before: :approve, on: :update, changed: :codename do
138
170
  errors.add :codename, 'only admins can set codename' unless Auth.always_ok?
139
171
  end
140
172
 
141
173
  event :validate_unique_codename, after: :permit_codename do
142
- if codename.present? and errors.empty? and Card.find_by_codename(codename).present?
174
+ if codename.present? && errors.empty? &&
175
+ Card.find_by_codename(codename).present?
143
176
  errors.add :codename, "codename #{codename} already in use"
144
177
  end
145
178
  end
@@ -147,45 +180,46 @@ end
147
180
  event :validate_name, before: :approve, on: :save do
148
181
  cdname = name.to_name
149
182
  if name.length > 255
150
- errors.add :name, "is too long (255 character maximum)"
183
+ errors.add :name, 'is too long (255 character maximum)'
151
184
  elsif cdname.blank?
152
185
  errors.add :name, "can't be blank"
153
186
  elsif name_changed?
154
- #Rails.logger.debug "valid name #{card.name.inspect} New #{name.inspect}"
187
+ # Rails.logger.debug "valid name #{card.name.inspect} New #{name.inspect}"
155
188
 
156
189
  unless cdname.valid?
157
- errors.add :name, "may not contain any of the following characters: #{ Card::Name.banned_array * ' ' }"
190
+ errors.add :name, 'may not contain any of the following characters: ' \
191
+ "#{ Card::Name.banned_array * ' ' }"
158
192
  end
159
193
  # this is to protect against using a plus card as a tag
160
- if cdname.junction? and simple? and id and Auth.as_bot { Card.count_by_wql right_id: id } > 0
194
+ if cdname.junction? && simple? && id &&
195
+ Auth.as_bot { Card.count_by_wql right_id: id } > 0
161
196
  errors.add :name, "#{name} in use as a tag"
162
197
  end
163
198
 
164
199
  # validate uniqueness of name
165
- condition_sql = "cards.key = ? and trash=?"
166
- condition_params = [ cdname.key, false ]
200
+ condition_sql = 'cards.key = ? and trash=?'
201
+ condition_params = [cdname.key, false]
167
202
  unless new_record?
168
- condition_sql << " AND cards.id <> ?"
203
+ condition_sql << ' AND cards.id <> ?'
169
204
  condition_params << id
170
205
  end
171
- if c = Card.find_by(condition_sql, *condition_params)
206
+ if (c = Card.find_by(condition_sql, *condition_params))
172
207
  errors.add :name, "must be unique; '#{c.name}' already exists."
173
208
  end
174
209
  end
175
210
  end
176
211
 
177
-
178
212
  event :set_autoname, before: :validate_name, on: :create do
179
- if name.blank? and autoname_card = rule_card(:autoname)
213
+ if name.blank? && (autoname_card = rule_card(:autoname))
180
214
  self.name = autoname autoname_card.content
181
- Auth.as_bot { autoname_card.refresh.update_attributes! content: name } #fixme, should give placeholder on new, do next and save on create
215
+ # FIXME: should give placeholder on new, do next and save on create
216
+ Auth.as_bot { autoname_card.refresh.update_attributes! content: name }
182
217
  end
183
218
  end
184
219
 
185
-
186
220
  event :validate_key, after: :validate_name, on: :save do
187
221
  if key.empty?
188
- errors.add :key, "cannot be blank" if errors.empty?
222
+ errors.add :key, 'cannot be blank' if errors.empty?
189
223
  elsif key != cardname.key
190
224
  errors.add :key, "wrong key '#{key}' for name #{name}"
191
225
  end
@@ -197,9 +231,12 @@ event :set_name, before: :store, changed: :name do
197
231
  if cardname.junction?
198
232
  [:left, :right].each do |side|
199
233
  sidename = cardname.send "#{side}_name"
200
- #warn "sidename #{name} / #{name_was} / #{cardname}, #{side}: #{sidename}"
234
+ # warn "sidename #{name} / #{name_was} / #{cardname},
235
+ # #{side}: #{sidename}"
201
236
  sidecard = Card[sidename]
202
- old_name_in_way = (sidecard && sidecard.id==self.id) # eg, renaming A to A+B
237
+
238
+ # eg, renaming A to A+B
239
+ old_name_in_way = (sidecard && sidecard.id == id)
203
240
  suspend_name(sidename) if old_name_in_way
204
241
  send "#{side}_id=", begin
205
242
  if !sidecard || old_name_in_way
@@ -214,60 +251,72 @@ event :set_name, before: :store, changed: :name do
214
251
  end
215
252
  end
216
253
 
217
-
218
254
  event :rename, after: :set_name, on: :update do
219
- if existing_card = Card.find_by_key_and_trash(cardname.key, true) and existing_card != self
220
- existing_card.name = existing_card.name+'*trash'
255
+ if (existing_card = Card.find_by_key_and_trash(cardname.key, true)) &&
256
+ existing_card != self
257
+ existing_card.name = existing_card.name + '*trash'
221
258
  existing_card.rename_without_callbacks
222
259
  existing_card.save!
223
260
  end
224
261
  end
225
262
 
226
- def suspend_name(name)
263
+ def suspend_name name
227
264
  # move the current card out of the way, in case the new name will require
228
265
  # re-creating a card with the current name, ie. A -> A+B
229
266
  Card.expire name
230
- tmp_name = "tmp:" + UUID.new.generate
231
- Card.where(id: self.id).update_all(name: tmp_name, key: tmp_name)
267
+ tmp_name = 'tmp:' + UUID.new.generate
268
+ Card.where(id: id).update_all(name: tmp_name, key: tmp_name)
232
269
  end
233
270
 
234
-
235
271
  event :cascade_name_changes, after: :store, on: :update, changed: :name do
236
- #Rails.logger.info "------------------- #{name_was} CASCADE #{self.name} -------------------------------------"
237
-
238
- self.update_referencers = false if self.update_referencers == 'false' #handle strings from cgi
272
+ # Rails.logger.info "------------------- #{name_was} CASCADE #{self.name} " \
273
+ # " -------------------------------------"
274
+ # handle strings from cgi
275
+ self.update_referencers = false if update_referencers == 'false'
239
276
  Card::Reference.update_on_rename self, name, self.update_referencers
240
277
 
241
- deps = self.dependents
242
- #warn "-------------------#{name_was}---- CASCADE #{self.name} -> deps: #{deps.map(&:name)*", "} -----------------------"
278
+ deps = dependents
279
+ # warn "-------------------#{name_was}---- CASCADE #{self.name} -> deps: " \
280
+ # " #{deps.map(&:name)*', '} -----------------------"
243
281
 
244
- @dependents = nil #reset
282
+ @dependents = nil # reset
245
283
 
246
284
  deps.each do |dep|
247
- # here we specifically want NOT to invoke recursive cascades on these cards, have to go this low level to avoid callbacks.
285
+ # here we specifically want NOT to invoke recursive cascades on these
286
+ # cards, have to go this low level to avoid callbacks.
248
287
  Rails.logger.info "cascading name: #{dep.name}"
249
- Card.expire dep.name #old name
288
+ Card.expire dep.name # old name
250
289
  newname = dep.cardname.replace_part name_was, name
251
- Card.where( id: dep.id ).update_all name: newname.to_s, key: newname.key
290
+ Card.where(id: dep.id).update_all name: newname.to_s, key: newname.key
252
291
  Card::Reference.update_on_rename dep, newname, update_referencers
253
292
  Card.expire newname
254
293
  end
255
- if update_referencers
256
- Auth.as_bot do
257
- [self.name_referencers(name_was)+(deps.map &:referencers)].flatten.uniq.each do |card|
258
- # FIXME using "name_referencers" instead of plain "referencers" for self because there are cases where trunk and tag
259
- # have already been saved via association by this point and therefore referencers misses things
260
- # eg. X includes Y, and Y is renamed to X+Z. When X+Z is saved, X is first updated as a trunk before X+Z gets to this point.
261
- # so at this time X is still including Y, which does not exist. therefore #referencers doesn't find it, but name_referencers(old_name) does.
262
- # some even more complicated scenario probably breaks on the dependents, so this probably needs a more thoughtful refactor
263
- # aligning the dependent saving with the name cascading
264
-
265
- Rails.logger.debug "------------------ UPDATE REFERER #{card.name} ------------------------"
266
- unless card == self or card.structure
267
- card = card.refresh
268
- card.db_content = card.replace_references name_was, name
269
- card.save!
270
- end
294
+ execute_referencers_update(deps) if update_referencers
295
+ end
296
+
297
+ def execute_referencers_update dependents
298
+ Auth.as_bot do
299
+ [name_referencers(name_was) + dependents.map(&:referencers)]
300
+ .flatten.uniq.each do |card|
301
+ # FIXME: using 'name_referencers' instead of plain 'referencers' for self
302
+ # because there are cases where trunk and tag
303
+ # have already been saved via association by this point and therefore
304
+ # referencers misses things
305
+ # eg. X includes Y, and Y is renamed to X+Z. When X+Z is saved, X is
306
+ # first updated as a trunk before X+Z gets to this point.
307
+ # so at this time X is still including Y, which does not exist.
308
+ # therefore #referencers doesn't find it, but name_referencers(old_name)
309
+ # does.
310
+ # some even more complicated scenario probably breaks on the dependents,
311
+ # so this probably needs a more thoughtful refactor
312
+ # aligning the dependent saving with the name cascading
313
+
314
+ Rails.logger.debug "------------------ UPDATE REFERER #{card.name} " \
315
+ '------------------------'
316
+ unless card == self || card.structure
317
+ card = card.refresh
318
+ card.db_content = card.replace_references name_was, name
319
+ card.save!
271
320
  end
272
321
  end
273
322
  end
@@ -1,31 +1,32 @@
1
1
 
2
- # The Card#abort method is for cleanly exiting an action without continuing to process any further events.
2
+ # The Card#abort method is for cleanly exiting an action without continuing
3
+ # to process any further events.
3
4
  #
4
5
  # Three statuses are supported:
5
6
  #
6
7
  # failure: adds an error, returns false on save
7
8
  # success: no error, returns true on save
8
- # triumph: similar to success, but if called on a subcard it causes the entire action to abort (not just the subcard)
9
+ # triumph: similar to success, but if called on a subcard
10
+ # it causes the entire action to abort (not just the subcard)
9
11
 
10
- def abort status, msg='action canceled'
12
+ def abort status, msg = 'action canceled'
11
13
  if status == :failure && errors.empty?
12
14
  errors.add :abort, msg
13
- elsif Hash === status and status[:success]
15
+ elsif Hash === status && status[:success]
14
16
  success << status[:success]
15
17
  status = :success
16
18
  end
17
- raise Card::Abort.new( status, msg)
19
+ raise Card::Abort.new(status, msg)
18
20
  end
19
21
 
20
-
21
22
  def abortable
22
23
  yield
23
24
  rescue Card::Abort => e
24
25
  if e.status == :triumph
25
- @supercard ? raise( e ) : true
26
+ @supercard ? raise(e) : true
26
27
  elsif e.status == :success
27
28
  if @supercard
28
- @supercard.subcards.delete_if { |k,v| v==self }
29
+ @supercard.subcards.delete(key)
29
30
  end
30
31
  true
31
32
  end
@@ -35,7 +36,8 @@ def valid_subcard?
35
36
  abortable { valid? }
36
37
  end
37
38
 
38
- # this is an override of standard rails behavior that rescues abortmakes it so that :success abortions do not rollback
39
+ # this is an override of standard rails behavior that rescues abort
40
+ # makes it so that :success abortions do not rollback
39
41
  def with_transaction_returning_status
40
42
  status = nil
41
43
  self.class.transaction do
@@ -47,78 +49,122 @@ def with_transaction_returning_status
47
49
  end
48
50
 
49
51
  # perhaps above should be in separate module?
50
- #~~~~~~
52
+ # ~~~~~~
53
+
54
+ PHASES = {}
55
+ [:prepare, :approve, :store, :stored, :extend, :subsequent]
56
+ .each_with_index do |phase, i|
57
+ PHASES[phase] = i
58
+ end
59
+
60
+ def run_phase phase, &block
61
+ @phase = phase
62
+ @subphase = :before
63
+ if block_given?
64
+ block.call
65
+ else
66
+ run_callbacks phase
67
+ end
68
+ @subphase = :after
69
+ end
70
+
71
+ def simulate_phase opts, &block
72
+ @phase
73
+ end
74
+
75
+ def phase
76
+ @phase || (@supercard && @supercard.phase)
77
+ end
78
+
79
+ def subphase
80
+ @subphase || (@supercard && @supercard.subphase)
81
+ end
51
82
 
52
83
  def prepare
53
84
  @action = identify_action
54
85
  # the following should really happen when type, name etc are changed
55
86
  reset_patterns
56
87
  include_set_modules
57
- run_callbacks :prepare
58
- rescue =>e
88
+ run_phase :prepare
89
+ rescue => e
59
90
  rescue_event e
60
91
  end
61
92
 
62
93
  def approve
63
94
  @action ||= identify_action
64
- run_callbacks :approve
95
+ run_phase :approve
65
96
  expire_pieces if errors.any?
66
97
  errors.empty?
67
- rescue =>e
98
+ rescue => e
68
99
  rescue_event e
69
100
  end
70
101
 
71
102
  def identify_action
72
103
  case
73
- when trash ; :delete
74
- when new_card? ; :create
75
- else :update
104
+ when trash then :delete
105
+ when new_card? then :create
106
+ else :update
76
107
  end
77
108
  end
78
109
 
79
-
80
110
  def store
81
- run_callbacks :store do
82
- yield #unless @draft
83
- @virtual = false
111
+ run_phase :store do
112
+ run_callbacks :store do
113
+ yield # unless @draft
114
+ @virtual = false
115
+ end
84
116
  end
85
- run_callbacks :stored
86
- rescue =>e
117
+ run_phase :stored
118
+ rescue => e
87
119
  rescue_event e
88
120
  ensure
89
- @from_trash = @last_action_id = @last_content_action_id = nil
121
+ @from_trash = @last_content_action_id = nil
90
122
  end
91
123
 
92
-
93
124
  def extend
94
-
95
- run_callbacks :extend
96
- run_callbacks :subsequent
97
- rescue =>e
125
+ run_phase :extend
126
+ run_phase :subsequent
127
+ rescue => e
98
128
  rescue_event e
99
129
  ensure
100
130
  @action = nil
101
131
  end
102
132
 
103
-
104
-
105
-
106
133
  def rescue_event e
107
134
  @action = nil
108
135
  expire_pieces
109
- subcards.each do |key, card|
110
- next unless Card===card
111
- card.expire_pieces
112
- end
136
+ subcards.each(&:expire_pieces)
113
137
  raise e
114
- #rescue Card::Cancel
115
- # false
138
+ # rescue Card::Cancel
139
+ # false
116
140
  end
117
141
 
118
- event :notable_exception_raised do
119
- Rails.logger.debug "BT: #{Card::Error.current.backtrace*"\n "}"
142
+ def phase_ok? opts
143
+ phase && (
144
+ (opts[:during] && in?(opts[:during])) ||
145
+ (opts[:before] && before?(opts[:before])) ||
146
+ (opts[:after] && after?(opts[:after]))
147
+ )
148
+ end
149
+
150
+ def before? allowed_phase
151
+ PHASES[allowed_phase] > PHASES[phase] ||
152
+ (PHASES[allowed_phase] == PHASES[phase] && subphase == :before)
120
153
  end
121
154
 
155
+ def after? allowed_phase
156
+ PHASES[allowed_phase] < PHASES[phase] ||
157
+ (PHASES[allowed_phase] == PHASES[phase] && subphase == :after)
158
+ end
159
+
160
+ def in? allowed_phase
161
+ (allowed_phase.is_a?(Array) && allowed_phase.include?(phase)) ||
162
+ allowed_phase == phase
163
+ end
164
+
165
+ event :notable_exception_raised do
166
+ Rails.logger.debug "BT: #{Card::Error.current.backtrace * "\n "}"
167
+ end
122
168
 
123
169
  def event_applies? opts
124
170
  on_condition_applies?(opts[:on]) &&
@@ -136,8 +182,13 @@ end
136
182
 
137
183
  def changed_condition_applies? db_column
138
184
  if db_column
139
- db_column = 'db_content' if db_column.to_sym == :content
140
- @action != :delete && changes[db_column.to_s]
185
+ db_column =
186
+ case db_column.to_sym
187
+ when :content then 'db_content'
188
+ when :type then 'type_id'
189
+ else db_column.to_s
190
+ end
191
+ @action != :delete && changes[db_column]
141
192
  else
142
193
  true
143
194
  end
@@ -151,59 +202,6 @@ def when_condition_applies? block
151
202
  end
152
203
  end
153
204
 
154
-
155
- def subcards
156
- @subcards ||= {}
157
- end
158
-
159
-
160
- event :process_subcards, after: :approve, on: :save do
161
- subcards.keys.each do |sub_name|
162
- opts = @subcards[sub_name] || {}
163
- opts = { 'content' => opts } if String===opts
164
- ab_name = sub_name.to_name.to_absolute_name name
165
- next if ab_name.key == key # don't resave self!
166
-
167
- opts = opts.stringify_keys
168
- opts['subcards'] = extract_subcard_args! opts
169
-
170
- opts[:supercard] = self
171
-
172
- subcard =
173
- if known_card = Card[ab_name]
174
- known_card.refresh.assign_attributes opts
175
- known_card
176
- elsif (opts['content'].present? && opts['content'].strip.present?) ||
177
- opts['subcards'].present? || opts['file'].present? || opts['image'].present?
178
- Card.new opts.reverse_merge 'name' => sub_name
179
- end
180
-
181
- if subcard
182
- @subcards[sub_name] = subcard
183
- else
184
- @subcards.delete sub_name
185
- end
186
- end
187
- end
188
-
189
- event :approve_subcards, after: :process_subcards do
190
- subcards.each do |key, subcard|
191
- if !subcard.valid_subcard?
192
- subcard.errors.each do |field, err|
193
- err = "#{field} #{err}" unless [:content, :abort].member? field
194
- errors.add subcard.relative_name, err
195
- end
196
- end
197
- end
198
- end
199
-
200
- event :store_subcards, after: :store do
201
- subcards.each do |key, sub|
202
- sub.save! validate: false #unless @draft
203
- end
204
- end
205
-
206
205
  def success
207
206
  Env.success(cardname)
208
207
  end
209
-