card 1.16.8 → 1.16.9
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/db/migrate_core_cards/{20150611203506_rails_inflection_updates.rb → 20120611203506_rails_inflection_updates.rb} +0 -0
- data/db/migrate_core_cards/20150326205655_bootswatch_themes.rb +0 -1
- data/db/migrate_core_cards/20150429090551_search_card_context.rb +1 -1
- data/db/migrate_core_cards/20150708224756_add_list_cards.rb +22 -0
- data/db/seed/new/card_actions.yml +789 -509
- data/db/seed/new/card_acts.yml +1 -1
- data/db/seed/new/card_changes.yml +2618 -1920
- data/db/seed/new/card_references.yml +1034 -901
- data/db/seed/new/cards.yml +2303 -1675
- data/db/seed/test/fixtures/card_actions.yml +1926 -1606
- data/db/seed/test/fixtures/card_acts.yml +354 -324
- data/db/seed/test/fixtures/card_changes.yml +5950 -5175
- data/db/seed/test/fixtures/card_references.yml +1861 -1630
- data/db/seed/test/fixtures/cards.yml +3768 -3048
- data/db/seed/test/seed.rb +121 -107
- data/lib/card.rb +2 -3
- data/lib/card/active_record_helper.rb +44 -0
- data/lib/card/auth.rb +51 -47
- data/lib/card/cache.rb +7 -3
- data/lib/card/codename.rb +7 -7
- data/lib/card/format.rb +2 -1
- data/lib/card/migration.rb +17 -16
- data/lib/card/name.rb +71 -20
- data/lib/card/set.rb +202 -166
- data/lib/card/simplecov_helper.rb +11 -7
- data/lib/card/subcards.rb +249 -0
- data/mod/01_core/set/all/collection.rb +1 -2
- data/mod/01_core/set/all/fetch.rb +167 -92
- data/mod/01_core/set/all/initialize.rb +8 -22
- data/mod/01_core/set/all/name.rb +128 -79
- data/mod/01_core/set/all/phases.rb +93 -95
- data/mod/01_core/set/all/subcards.rb +70 -0
- data/mod/01_core/set/all/tracked_attributes.rb +83 -59
- data/mod/01_core/set/all/trash.rb +14 -12
- data/mod/01_core/set/all/type.rb +3 -24
- data/mod/01_core/spec/set/all/initialize_spec.rb +44 -14
- data/mod/01_core/spec/set/all/permissions_spec.rb +206 -185
- data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +0 -10
- data/mod/01_core/spec/set/all/trash_spec.rb +38 -13
- data/mod/01_core/spec/set/all/type_spec.rb +0 -19
- data/mod/01_history/set/all/content_history.rb +5 -3
- data/mod/01_history/set/all/history.rb +117 -82
- data/mod/02_basic_types/set/all/base.rb +50 -49
- data/mod/03_machines/lib/card/machine.rb +2 -1
- data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +55 -17
- data/mod/03_machines/spec/set/type/javascript_spec.rb +18 -12
- data/mod/05_email/set/right/followers.rb +5 -5
- data/mod/05_email/set/right/following.rb +1 -1
- data/mod/05_email/set/type_plus_right/user/follow.rb +1 -1
- data/mod/05_standard/lib/carrier_wave/cardmount.rb +19 -11
- data/mod/05_standard/lib/file_uploader.rb +1 -1
- data/mod/05_standard/set/abstract/attachment.rb +20 -8
- data/mod/05_standard/set/all/list_changes.rb +43 -0
- data/mod/05_standard/set/all/rich_html/form.rb +21 -11
- data/mod/05_standard/set/all/rich_html/menu.rb +1 -1
- data/mod/05_standard/set/right/account.rb +5 -5
- data/mod/05_standard/set/self/head.rb +0 -1
- data/mod/05_standard/set/self/signin.rb +43 -35
- data/mod/05_standard/set/type/file.rb +9 -2
- data/mod/05_standard/set/type/list.rb +134 -0
- data/mod/05_standard/set/type/listed_by.rb +94 -0
- data/mod/05_standard/set/type/search_type.rb +62 -61
- data/mod/05_standard/set/type/signup.rb +94 -63
- data/mod/05_standard/set/type/user.rb +48 -39
- data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
- data/mod/05_standard/spec/set/all/rich_html/form_spec.rb +2 -2
- data/mod/05_standard/spec/set/self/signin_spec.rb +23 -27
- data/mod/05_standard/spec/set/type/email_template_spec.rb +0 -2
- data/mod/05_standard/spec/set/type/list_spec.rb +140 -0
- data/mod/05_standard/spec/set/type/listed_by_spec.rb +157 -0
- data/mod/05_standard/spec/set/type/signup_spec.rb +38 -32
- data/spec/lib/card/subcards_spec.rb +126 -0
- 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={},
|
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']
|
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
|
-
|
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
|
data/mod/01_core/set/all/name.rb
CHANGED
@@ -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
|
-
@
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
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
|
-
|
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
|
50
|
-
|
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
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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(
|
97
|
+
Card.fetch(cardname.right, *args) if !simple?
|
66
98
|
end
|
67
99
|
|
68
100
|
def [] *args
|
69
|
-
|
101
|
+
case args[0]
|
102
|
+
when Fixnum, Range
|
70
103
|
fetch_name = Array.wrap(cardname.parts[args[0]]).compact.join '+'
|
71
|
-
Card.fetch(
|
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(
|
111
|
+
simple? ? self : left(*args)
|
79
112
|
end
|
80
113
|
|
81
114
|
def tag *args
|
82
|
-
simple? ? self : Card.fetch(
|
115
|
+
simple? ? self : Card.fetch(cardname.right, *args)
|
83
116
|
end
|
84
117
|
|
85
118
|
def left_or_new args={}
|
86
|
-
left
|
119
|
+
left(args) || Card.new(args.merge(name: cardname.left))
|
87
120
|
end
|
88
121
|
|
89
122
|
def children
|
90
|
-
Card.search(
|
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 = (
|
121
|
-
saved ||= (
|
153
|
+
saved = (self.key = correct_key) && self.save!
|
154
|
+
saved ||= (self.cardname = current_key) && self.save!
|
122
155
|
|
123
156
|
if saved
|
124
|
-
|
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?
|
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,
|
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,
|
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?
|
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 =
|
166
|
-
condition_params = [
|
200
|
+
condition_sql = 'cards.key = ? and trash=?'
|
201
|
+
condition_params = [cdname.key, false]
|
167
202
|
unless new_record?
|
168
|
-
condition_sql <<
|
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?
|
213
|
+
if name.blank? && (autoname_card = rule_card(:autoname))
|
180
214
|
self.name = autoname autoname_card.content
|
181
|
-
|
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,
|
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},
|
234
|
+
# warn "sidename #{name} / #{name_was} / #{cardname},
|
235
|
+
# #{side}: #{sidename}"
|
201
236
|
sidecard = Card[sidename]
|
202
|
-
|
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)
|
220
|
-
|
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
|
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 =
|
231
|
-
Card.where(id:
|
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
|
-
|
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 =
|
242
|
-
#warn "-------------------#{name_was}---- CASCADE #{self.name} -> deps:
|
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
|
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(
|
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
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
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
|
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
|
15
|
+
elsif Hash === status && status[:success]
|
14
16
|
success << status[:success]
|
15
17
|
status = :success
|
16
18
|
end
|
17
|
-
raise Card::Abort.new(
|
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(
|
26
|
+
@supercard ? raise(e) : true
|
26
27
|
elsif e.status == :success
|
27
28
|
if @supercard
|
28
|
-
@supercard.subcards.
|
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
|
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
|
-
|
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
|
-
|
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
|
74
|
-
when new_card?
|
75
|
-
else
|
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
|
-
|
82
|
-
|
83
|
-
|
111
|
+
run_phase :store do
|
112
|
+
run_callbacks :store do
|
113
|
+
yield # unless @draft
|
114
|
+
@virtual = false
|
115
|
+
end
|
84
116
|
end
|
85
|
-
|
86
|
-
rescue =>e
|
117
|
+
run_phase :stored
|
118
|
+
rescue => e
|
87
119
|
rescue_event e
|
88
120
|
ensure
|
89
|
-
@from_trash =
|
121
|
+
@from_trash = @last_content_action_id = nil
|
90
122
|
end
|
91
123
|
|
92
|
-
|
93
124
|
def extend
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
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
|
-
#
|
138
|
+
# rescue Card::Cancel
|
139
|
+
# false
|
116
140
|
end
|
117
141
|
|
118
|
-
|
119
|
-
|
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 =
|
140
|
-
|
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
|
-
|