card 1.19.1 → 1.19.2
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.
- checksums.yaml +4 -4
- data/.yardopts +3 -3
- data/VERSION +1 -1
- data/db/migrate_core_cards/20160908154210_add_trash_card.rb +7 -0
- data/lib/card.rb +2 -2
- data/lib/card/act_manager.rb +143 -0
- data/lib/card/act_manager/stage.rb +56 -0
- data/lib/card/act_manager/stage_director.rb +313 -0
- data/lib/card/act_manager/subdirector_array.rb +43 -0
- data/lib/card/set.rb +1 -0
- data/lib/card/set/i18n_scope.rb +52 -0
- data/lib/card/subcards.rb +2 -3
- data/lib/cardio.rb +4 -4
- data/mod/admin/set/self/admin.rb +1 -2
- data/mod/admin/set/self/trash.rb +29 -0
- data/mod/core/set/abstract/code_file.rb +5 -25
- data/mod/core/set/all/actify.rb +35 -0
- data/mod/core/set/all/fetch.rb +12 -15
- data/mod/core/set/all/i18n.rb +9 -0
- data/mod/core/set/all/phases.rb +1 -1
- data/mod/core/set/all/stages.rb +2 -2
- data/mod/developer/set/all/event_viz.rb +2 -1
- data/mod/email/set/all/notify.rb +1 -1
- data/mod/history/lib/card/act.rb +1 -1
- data/mod/history/lib/card/action.rb +1 -1
- data/mod/history/set/all/history.rb +1 -1
- data/mod/machines/set/abstract/machine.rb +1 -1
- data/mod/machines/spec/set/type/coffeescript_spec.rb +1 -1
- data/mod/machines/spec/set/type/css_spec.rb +1 -1
- data/mod/machines/spec/set/type/javascript_spec.rb +1 -1
- data/mod/machines/spec/set/type/scss_spec.rb +1 -1
- data/mod/machines/spec/set/type/skin_spec.rb +1 -1
- data/mod/machines/spec/{lib/shared_machine_examples.rb → shared_examples/machine.rb} +15 -24
- data/mod/machines/spec/{lib/shared_machine_input_examples.rb → shared_examples/machine_input.rb} +0 -0
- data/mod/settings/spec/set/right/script_spec.rb +1 -1
- data/mod/settings/spec/set/right/style_spec.rb +1 -4
- data/mod/solid_cache/set/abstract/solid_cache.rb +1 -1
- data/spec/lib/card/content_spec.rb +118 -132
- data/spec/lib/card/i18n_spec.rb +6 -7
- data/spec/lib/card/query_spec.rb +5 -4
- data/spec/lib/card/stage_director_spec.rb +1 -1
- data/spec/spec_helper.rb +3 -4
- data/tmpsets/set/{mod002-core → mod001-core}/abstract/code_file.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/actify.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/active_card.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/collection.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/content.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/erb.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/event.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/export.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/fetch.rb +12 -14
- data/tmpsets/set/{mod002-core → mod001-core}/all/haml.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/initialize.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/location_history.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/name.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/name_validations.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/pattern.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/permissions.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/phases.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/references.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/rules.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/stages.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/states.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/subcards.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/templating.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/tracked_attributes.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/trash.rb +0 -50
- data/tmpsets/set/{mod002-core → mod001-core}/all/type.rb +0 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/utils.rb +33 -0
- data/tmpsets/set/{mod002-core → mod001-core}/all/view_cache.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/actions.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/content_history.rb +0 -0
- data/tmpsets/set/{mod003-history → mod002-history}/all/history.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_css.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_csv.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/all_js.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/base.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/file.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/json.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/rss.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/all/text.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/self/01_head/javascript.rb +0 -0
- data/tmpsets/set/{mod004-basic_formats → mod003-basic_formats}/self/head.rb +1 -1
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/01_pointer.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/01_pointer/edit.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/abstract/code_pointer.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_editors.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_mods.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/self/script_pointer_config.rb +0 -0
- data/tmpsets/set/{mod005-pointer → mod004-pointer}/type/pointer.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/abstract/ace_editor.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/self/script_ace.rb +0 -0
- data/tmpsets/set/{mod006-ace_editor → mod005-ace_editor}/self/script_ace_config.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/abstract/prosemirror_editor.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/self/script_prosemirror.rb +0 -0
- data/tmpsets/set/{mod007-prosemirror_editor → mod006-prosemirror_editor}/self/script_prosemirror_config.rb +0 -0
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/abstract/solid_cache.rb +1 -1
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/all/solid_cache.rb +0 -0
- data/tmpsets/set/{mod009-solid_cache → mod008-solid_cache}/right/solid_cache.rb +0 -0
- data/tmpsets/set/{mod010-basic_types → mod009-basic_types}/type/html.rb +0 -0
- data/tmpsets/set/{mod010-basic_types → mod009-basic_types}/type/plain_text.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/abstract/script.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/all/reset_machines.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_cache.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_input.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/right/machine_output.rb +1 -9
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_card_menu.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_html5shiv_printshiv.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_jquery.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_jquery_helper.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/script_slot.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_bootstrap_compatible.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_cards.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/self/style_jquery_ui_smoothness.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/coffee_script.rb +6 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/css.rb +2 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/java_script.rb +2 -2
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/scss.rb +0 -0
- data/tmpsets/set/{mod011-machines → mod010-machines}/type/skin.rb +2 -2
- data/tmpsets/set/{mod012-settings → mod011-settings}/abstract/permission.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/add_help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/comment.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/default.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/read.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/script.rb +1 -1
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/structure.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/style.rb +1 -1
- data/tmpsets/set/{mod012-settings → mod011-settings}/right/update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/accountable.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/add_help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/autoname.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/captcha.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/default.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/default_html_view.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/follow_fields.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/help.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/input.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/layout.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_create.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_delete.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/on_update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/options.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/options_label.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/read.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/recent_settings.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/script.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/structure.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/style.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/table_of_contents.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/thanks.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/self/update.rb +0 -0
- data/tmpsets/set/{mod012-settings → mod011-settings}/type/setting.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/email_html.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/email_text.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/notify.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/all/observer.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/bcc.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/cc.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/follow_fields.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/followers.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/following.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/from.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/html_message.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/right/to.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/always.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/created.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/edited.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/follow.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/follow_defaults.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/self/never.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/type/email_template.rb +0 -0
- data/tmpsets/set/{mod013-email → mod012-email}/type_plus_right/user/follow.rb +8 -4
- data/tmpsets/set/mod016-standard/all/links.rb +2 -2
- data/tmpsets/set/mod018-bootstrap/all/bootstrap/table.rb +1 -1
- data/tmpsets/set/mod018-bootstrap/self/bootswatch_shared.rb +1 -1
- metadata +149 -163
- data/lib/card/director_register.rb +0 -101
- data/lib/card/stage.rb +0 -106
- data/lib/card/stage_director.rb +0 -310
- data/lib/card/subdirector_array.rb +0 -43
- data/tmpsets/set/mod001-admin/self/admin.rb +0 -130
- data/tmpsets/set/mod001-admin/self/admin_info.rb +0 -110
- data/tmpsets/set/mod001-admin/self/version.rb +0 -15
- data/tmpsets/set/mod002-core/all/debug.rb +0 -30
- data/tmpsets/set/mod002-core/all/update_read_rules.rb +0 -91
- data/tmpsets/set/mod011-machines/abstract/machine.rb +0 -277
- data/tmpsets/set/mod011-machines/abstract/machine_input.rb +0 -83
- data/tmpsets/set/mod014-developer/all/event_viz.rb +0 -59
- data/tmpsets/set/mod014-developer/all/view_viz.rb +0 -30
- data/tmpsets/set/mod014-developer/right/debug.rb +0 -96
- data/tmpsets/set/mod015-carrierwave/abstract/attachment.rb +0 -118
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/paths.rb +0 -57
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/storage_type.rb +0 -326
- data/tmpsets/set/mod015-carrierwave/abstract/attachment/upload_cache.rb +0 -84
- data/tmpsets/set/mod015-carrierwave/all/file_utils.rb +0 -35
- data/tmpsets/set/mod015-carrierwave/self/admin.rb +0 -30
- data/tmpsets/set/mod015-carrierwave/type/file.rb +0 -158
- data/tmpsets/set/mod015-carrierwave/type/image.rb +0 -97
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c530f9f078a90e9de4c239d7f5222e670b10b98a
|
|
4
|
+
data.tar.gz: 735604a8c31fe1247d23e3bbc5c90d495c83593a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 43e1f744865904f81aec258a25a0f823693b2b8b418491e451594a18f345fb4b79e796ece4ca46e4c9ac604c9622646faf137801353348802d7b5c790d14e270
|
|
7
|
+
data.tar.gz: 6224a80edc261e7b8636dce40fdb1357ee1d94e08c4fc32208587f6470b413c4e3af370156bfb1d9553159a5872245cc10cf1fb304d94d7413d50da90c8a4969
|
data/.yardopts
CHANGED
data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.19.
|
|
1
|
+
1.19.2
|
data/lib/card.rb
CHANGED
|
@@ -42,8 +42,8 @@ class Card < ActiveRecord::Base
|
|
|
42
42
|
require_dependency "card/reference"
|
|
43
43
|
require_dependency "card/subcards"
|
|
44
44
|
require_dependency "card/cache/view_cache"
|
|
45
|
-
require_dependency "card/
|
|
46
|
-
require_dependency "card/
|
|
45
|
+
require_dependency "card/act_manager"
|
|
46
|
+
require_dependency "card/act_manager/stage_director"
|
|
47
47
|
|
|
48
48
|
has_many :references_in, class_name: :Reference, foreign_key: :referee_id
|
|
49
49
|
has_many :references_out, class_name: :Reference, foreign_key: :referer_id
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
class Card
|
|
2
|
+
# Manages the whole process of creating an {act Card::Act} ie. changing
|
|
3
|
+
# a card and attached subcards.
|
|
4
|
+
#
|
|
5
|
+
# For every card that is part of the act the ActManager creates a
|
|
6
|
+
# {StageDirector} that leads the card through all the stages.
|
|
7
|
+
# Because cards sometimes get expired and reloaded during an act we need
|
|
8
|
+
# this global object to ensure that the stage information doesn't get lost
|
|
9
|
+
# until the act is finished.
|
|
10
|
+
#
|
|
11
|
+
# The process of creating an act/writing a card change to the database
|
|
12
|
+
# is divided into 8 stages that are grouped in 3 phases.
|
|
13
|
+
#
|
|
14
|
+
# 'validation phase'
|
|
15
|
+
# * initialize stage (I)
|
|
16
|
+
# * prepare_to_validate stage (P2V)
|
|
17
|
+
# * validate stage (V)
|
|
18
|
+
#
|
|
19
|
+
# 'storage phase'
|
|
20
|
+
# * prepare_to_store stage (P2S)
|
|
21
|
+
# * store stage (S)
|
|
22
|
+
# * finalize stage (F)
|
|
23
|
+
#
|
|
24
|
+
# 'integration phase'
|
|
25
|
+
# * integrate stage (IG)
|
|
26
|
+
# * integrate_with_delay stage (IGwD)
|
|
27
|
+
#
|
|
28
|
+
#
|
|
29
|
+
# The table below gives you an overview what you can do in which stage:
|
|
30
|
+
#
|
|
31
|
+
# validation | storage | integration
|
|
32
|
+
# I P2V V | P2S S F | IG IGwD
|
|
33
|
+
#-------------------------------------------------------------------------
|
|
34
|
+
# attach subcard yes! yes! yes | yes yes yes | yes
|
|
35
|
+
# detach subcard yes! yes! yes | yes no no! | no!
|
|
36
|
+
# validate yes yes yes! | no | no
|
|
37
|
+
# 1 insecure change yes yes! no | no! | no!
|
|
38
|
+
# 2 secure change yes | yes! no! no! | no!
|
|
39
|
+
# abort yes! | yes | yes?
|
|
40
|
+
# add errors yes! | no! | no!
|
|
41
|
+
# 3 create other cards yes | yes | yes
|
|
42
|
+
# has id no | no no? yes | yes
|
|
43
|
+
# within web request yes | yes | yes no
|
|
44
|
+
# 4 within transaction yes | yes | no
|
|
45
|
+
|
|
46
|
+
# available values:
|
|
47
|
+
# dirty attributes yes | yes | yes
|
|
48
|
+
# params yes | yes | yes
|
|
49
|
+
# success yes | yes | yes no
|
|
50
|
+
# session yes | yes | yes no
|
|
51
|
+
#
|
|
52
|
+
#
|
|
53
|
+
# Explanation:
|
|
54
|
+
# yes! the recommended stage to do that
|
|
55
|
+
# yes ok to do it here
|
|
56
|
+
# no not recommended; chance to mess things up
|
|
57
|
+
# but if something forces you to do it here you can try
|
|
58
|
+
# no! never do it here. it won't work or will break things
|
|
59
|
+
#
|
|
60
|
+
# if there is only a single entry in a phase column it counts for all stages
|
|
61
|
+
# of that phase
|
|
62
|
+
#
|
|
63
|
+
# 1) 'insecure' means a change of a card attribute that can possibly make
|
|
64
|
+
# the card invalid to save
|
|
65
|
+
# 2) 'secure' means you are sure that the change doesn't affect the validation
|
|
66
|
+
# 3) If you call 'create', 'update_attributes' or 'save' the card will become
|
|
67
|
+
# part of the same act and all stage of the validation and storage phase
|
|
68
|
+
# will be executed immediately for that card. The integration phase will be
|
|
69
|
+
# executed together with the act card and its subcards
|
|
70
|
+
# 4) This means if an exception is raised in the validation or storage phase
|
|
71
|
+
# everything will rollback. If the integration phase fails the db changes
|
|
72
|
+
# of the other two phases will remain persistent.
|
|
73
|
+
class ActManager
|
|
74
|
+
cattr_accessor :act_card
|
|
75
|
+
|
|
76
|
+
class << self
|
|
77
|
+
def act_director
|
|
78
|
+
return unless act_card
|
|
79
|
+
act_card.director
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def directors
|
|
83
|
+
@directors ||= {}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def clear
|
|
87
|
+
ActManager.act_card = nil
|
|
88
|
+
directors.each_pair do |card, _dir|
|
|
89
|
+
card.director = nil
|
|
90
|
+
end
|
|
91
|
+
@directors = nil
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def fetch card, opts={}
|
|
95
|
+
return directors[card] if directors[card]
|
|
96
|
+
directors.each_key do |dir_card|
|
|
97
|
+
return dir_card.director if dir_card.name == card.name
|
|
98
|
+
end
|
|
99
|
+
directors[card] = new_director card, opts
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def new_director card, opts={}
|
|
103
|
+
if opts[:parent]
|
|
104
|
+
StageSubdirector.new card, opts
|
|
105
|
+
elsif act_card && act_card != card && running_act?
|
|
106
|
+
act_card.director.subdirectors.add card
|
|
107
|
+
else
|
|
108
|
+
StageDirector.new card
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def add director
|
|
113
|
+
directors[director.card] = director
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def card_changed old_card
|
|
117
|
+
return unless (director = @directors.delete old_card)
|
|
118
|
+
add director
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def delete director
|
|
122
|
+
return unless @directors
|
|
123
|
+
@directors.delete director.card
|
|
124
|
+
director.delete
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def deep_delete director
|
|
128
|
+
director.subdirectors.each do |subdir|
|
|
129
|
+
deep_delete subdir
|
|
130
|
+
end
|
|
131
|
+
delete director
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def running_act?
|
|
135
|
+
(dir = act_director) && dir.running?
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def to_s
|
|
139
|
+
directors.values.map(&:to_s).join "\n"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
class Card
|
|
2
|
+
class ActManager
|
|
3
|
+
module Stage
|
|
4
|
+
STAGES = [:initialize, :prepare_to_validate, :validate, :prepare_to_store,
|
|
5
|
+
:store, :finalize, :integrate, :integrate_with_delay].freeze
|
|
6
|
+
stage_index = {}
|
|
7
|
+
STAGES.each_with_index do |stage, i|
|
|
8
|
+
stage_index[stage] = i
|
|
9
|
+
end
|
|
10
|
+
STAGE_INDEX = stage_index.freeze
|
|
11
|
+
|
|
12
|
+
def stage_symbol index
|
|
13
|
+
case index
|
|
14
|
+
when Symbol
|
|
15
|
+
return index if STAGE_INDEX[index]
|
|
16
|
+
when Integer
|
|
17
|
+
return STAGES[index] if index < STAGES.size
|
|
18
|
+
end
|
|
19
|
+
raise Card::Error, "not a valid stage index: #{index}"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def stage_index stage
|
|
23
|
+
case stage
|
|
24
|
+
when Symbol then
|
|
25
|
+
return STAGE_INDEX[stage]
|
|
26
|
+
when Integer then
|
|
27
|
+
return stage
|
|
28
|
+
else
|
|
29
|
+
raise Card::Error, "not a valid stage: #{stage}"
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def stage_ok? opts
|
|
34
|
+
stage && (
|
|
35
|
+
(opts[:during] && in?(opts[:during])) ||
|
|
36
|
+
(opts[:before] && before?(opts[:before])) ||
|
|
37
|
+
(opts[:after] && after?(opts[:after])) ||
|
|
38
|
+
true # no phase restriction in opts
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def before? allowed_phase
|
|
43
|
+
STAGE_INDEX[allowed_phase] > STAGE_INDEX[stage]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def after? allowed_phase
|
|
47
|
+
STAGE_INDEX[allowed_phase] < STAGE_INDEX[stage]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def in? allowed_phase
|
|
51
|
+
(allowed_phase.is_a?(Array) && allowed_phase.include?(stage)) ||
|
|
52
|
+
allowed_phase == stage
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
|
|
2
|
+
class Card
|
|
3
|
+
def restore_changes_information
|
|
4
|
+
return unless @previously_changed
|
|
5
|
+
@changed_attributes = ActiveSupport::HashWithIndifferentAccess.new
|
|
6
|
+
@previously_changed.each do |k, (old, _new)|
|
|
7
|
+
@changed_attributes[k] = old
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def clean_after_stage_fail
|
|
12
|
+
@action = nil
|
|
13
|
+
expire_pieces
|
|
14
|
+
subcards.each(&:expire_pieces)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class ActManager
|
|
18
|
+
# A 'StageDirector' executes the stages of a card when the card gets
|
|
19
|
+
# created, updated or deleted.
|
|
20
|
+
# For subcards, i.e. other cards that are changed in the same act, a
|
|
21
|
+
# StageDirector has StageSubdirectors that take care of the stages for
|
|
22
|
+
# those cards
|
|
23
|
+
#
|
|
24
|
+
# In general a stage is executed for all involved cards before the
|
|
25
|
+
# StageDirector proceeds with the next stage.
|
|
26
|
+
# Only exception is the finalize stage.
|
|
27
|
+
# The finalize stage of a subcard is executed immediately after its store
|
|
28
|
+
# stage. When all subcards are finalized the supercard's finalize stage is
|
|
29
|
+
# executed.
|
|
30
|
+
#
|
|
31
|
+
# If a subcard is added in a stage then it catches up at the end of the
|
|
32
|
+
# stage to the current stage.
|
|
33
|
+
# For example if you add a subcard in a card's :prepare_to_store stage then
|
|
34
|
+
# after that stage the stages :initialize, :prepare_to_validate,
|
|
35
|
+
# :validate and :prepare_to_store are executed for the subcard.
|
|
36
|
+
#
|
|
37
|
+
# Stages are executed with pre-order depth-first search.
|
|
38
|
+
# That means if A has subcards AA and AB; AAA is subcard of AA and ABA
|
|
39
|
+
# subcard of AB then the order of execution is
|
|
40
|
+
# A -> AA -> AAA -> AB -> ABA
|
|
41
|
+
#
|
|
42
|
+
# A special case can happen in the store phase.
|
|
43
|
+
# If the id of a subcard is needed for a supercard
|
|
44
|
+
# (for example as left_id or as type_id) and the subcard doesn't
|
|
45
|
+
# have an id yet (because it gets created in the same act)
|
|
46
|
+
# then the subcard's store stage is executed before the supercard's store
|
|
47
|
+
# stage
|
|
48
|
+
class StageDirector
|
|
49
|
+
include Stage
|
|
50
|
+
|
|
51
|
+
attr_accessor :prior_store, :act, :card, :stage, :parent, :main,
|
|
52
|
+
:subdirectors, :transact_in_stage
|
|
53
|
+
attr_reader :running
|
|
54
|
+
alias_method :running?, :running
|
|
55
|
+
alias_method :main?, :main
|
|
56
|
+
|
|
57
|
+
def initialize card, opts={}, main=true
|
|
58
|
+
@card = card
|
|
59
|
+
@card.director = self
|
|
60
|
+
# for read actions there is no validation phase
|
|
61
|
+
# so we have to set the action here
|
|
62
|
+
@card.identify_action
|
|
63
|
+
|
|
64
|
+
@stage = nil
|
|
65
|
+
@running = false
|
|
66
|
+
@prepared = false
|
|
67
|
+
@parent = opts[:parent]
|
|
68
|
+
# has card to be stored before the supercard?
|
|
69
|
+
@prior_store = opts[:priority]
|
|
70
|
+
@call_after_store = []
|
|
71
|
+
@main = main
|
|
72
|
+
@subdirectors = SubdirectorArray.initialize_with_subcards(self)
|
|
73
|
+
register
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def register
|
|
77
|
+
ActManager.add self
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def unregister
|
|
81
|
+
ActManager.delete self
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def delete
|
|
85
|
+
@card.director = nil
|
|
86
|
+
@subdirectors.clear
|
|
87
|
+
@stage = nil
|
|
88
|
+
@action = nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def prepare_for_phases
|
|
92
|
+
@card.prepare_for_phases unless @prepared
|
|
93
|
+
@prepared = true
|
|
94
|
+
@subdirectors.each(&:prepare_for_phases)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def validation_phase
|
|
98
|
+
run_single_stage :initialize
|
|
99
|
+
run_single_stage :prepare_to_validate
|
|
100
|
+
run_single_stage :validate
|
|
101
|
+
@card.expire_pieces if @card.errors.any?
|
|
102
|
+
@card.errors.empty?
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def storage_phase &block
|
|
106
|
+
catch_up_to_stage :prepare_to_store
|
|
107
|
+
run_single_stage :store, &block
|
|
108
|
+
run_single_stage :finalize
|
|
109
|
+
ensure
|
|
110
|
+
@from_trash = nil
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def integration_phase
|
|
114
|
+
return if @abort
|
|
115
|
+
@card.restore_changes_information
|
|
116
|
+
run_single_stage :integrate
|
|
117
|
+
run_single_stage :integrate_with_delay
|
|
118
|
+
rescue => e # don't rollback
|
|
119
|
+
Card::Error.current = e
|
|
120
|
+
@card.notable_exception_raised
|
|
121
|
+
return false
|
|
122
|
+
ensure
|
|
123
|
+
@card.changes_applied unless @abort
|
|
124
|
+
ActManager.clear if main? && !@card.only_storage_phase
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def catch_up_to_stage next_stage
|
|
128
|
+
if @transact_in_stage
|
|
129
|
+
return if @transact_in_stage != next_stage
|
|
130
|
+
next_stage = :integrate_with_delay
|
|
131
|
+
end
|
|
132
|
+
upto_stage(next_stage) do |stage|
|
|
133
|
+
run_single_stage stage
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def reset_stage
|
|
138
|
+
@stage = -1
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def abort
|
|
142
|
+
@abort = true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def call_after_store &block
|
|
146
|
+
@call_after_store << block
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def need_act
|
|
150
|
+
act_director = main_director
|
|
151
|
+
unless act_director
|
|
152
|
+
raise Card::Error, "act requested without a main stage director"
|
|
153
|
+
end
|
|
154
|
+
act_director.act ||= Card::Act.create(ip_address: Env.ip)
|
|
155
|
+
@card.current_act = @act = act_director.act
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def main_director
|
|
159
|
+
if main?
|
|
160
|
+
self
|
|
161
|
+
else
|
|
162
|
+
ActManager.act_director || (@parent && @parent.main_director)
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def to_s
|
|
167
|
+
str = @card.name.to_s.clone
|
|
168
|
+
if @subdirectors
|
|
169
|
+
subs = subdirectors.map(&:card)
|
|
170
|
+
.map { |card| " #{card.name}" }.join "\n"
|
|
171
|
+
str << "\n#{subs}"
|
|
172
|
+
end
|
|
173
|
+
str
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def update_card card
|
|
177
|
+
old_card = @card
|
|
178
|
+
@card = card
|
|
179
|
+
ActManager.card_changed old_card
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
private
|
|
183
|
+
|
|
184
|
+
def upto_stage stage
|
|
185
|
+
@stage ||= -1
|
|
186
|
+
(@stage + 1).upto(stage_index(stage)) do |i|
|
|
187
|
+
yield stage_symbol(i)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def valid_next_stage? stage
|
|
192
|
+
new_stage = stage_index(stage)
|
|
193
|
+
@stage ||= -1
|
|
194
|
+
return if @stage >= new_stage
|
|
195
|
+
if @stage < new_stage - 1
|
|
196
|
+
raise Card::Error, "stage #{stage_symbol(new_stage - 1)} was " \
|
|
197
|
+
"skipped for card #{@card}"
|
|
198
|
+
end
|
|
199
|
+
@card.errors.empty? || new_stage > stage_index(:validate)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
def run_single_stage stage, &block
|
|
203
|
+
return true unless valid_next_stage? stage
|
|
204
|
+
# puts "#{@card.name}: #{stage} stage".red
|
|
205
|
+
|
|
206
|
+
@stage = stage_index stage
|
|
207
|
+
if stage == :initialize
|
|
208
|
+
@running ||= true
|
|
209
|
+
prepare_for_phases
|
|
210
|
+
end
|
|
211
|
+
# in the store stage it can be necessary that
|
|
212
|
+
# other subcards must be saved before we save this card
|
|
213
|
+
if stage == :store
|
|
214
|
+
store(&block)
|
|
215
|
+
else
|
|
216
|
+
run_stage_callbacks stage
|
|
217
|
+
run_subdirector_stages stage
|
|
218
|
+
end
|
|
219
|
+
rescue => e
|
|
220
|
+
@card.clean_after_stage_fail
|
|
221
|
+
raise e
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def run_stage_callbacks stage
|
|
225
|
+
Rails.logger.debug "#{stage}: #{@card.name}"
|
|
226
|
+
# we use abort :success in the :store stage for :save_draft
|
|
227
|
+
if stage_index(stage) <= stage_index(:store) && !main?
|
|
228
|
+
@card.abortable do
|
|
229
|
+
@card.run_callbacks :"#{stage}_stage"
|
|
230
|
+
end
|
|
231
|
+
else
|
|
232
|
+
@card.run_callbacks :"#{stage}_stage"
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def run_subdirector_stages stage
|
|
237
|
+
@subdirectors.each do |subdir|
|
|
238
|
+
subdir.catch_up_to_stage stage
|
|
239
|
+
end
|
|
240
|
+
ensure
|
|
241
|
+
@card.handle_subcard_errors
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# handle the store stage
|
|
245
|
+
# The tricky part here is to preserve the dirty marks on the subcards'
|
|
246
|
+
# attributes for the finalize stage.
|
|
247
|
+
# To achieve this we can't just call the :store and :finalize callbacks on
|
|
248
|
+
# the subcards as we do in the other phases.
|
|
249
|
+
# Instead we have to call `save` on the subcards
|
|
250
|
+
# and use the ActiveRecord :around_save callback to run the :store and
|
|
251
|
+
# :finalize stages
|
|
252
|
+
def store &save_block
|
|
253
|
+
if main? && !block_given?
|
|
254
|
+
raise Card::Error, "need block to store main card"
|
|
255
|
+
end
|
|
256
|
+
# the block is the ActiveRecord block from the around save callback that
|
|
257
|
+
# saves the card
|
|
258
|
+
if block_given?
|
|
259
|
+
run_stage_callbacks :store
|
|
260
|
+
store_with_subcards(&save_block)
|
|
261
|
+
else
|
|
262
|
+
trigger_storage_phase_callback
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def store_with_subcards
|
|
267
|
+
store_pre_subcards
|
|
268
|
+
yield
|
|
269
|
+
@call_after_store.each { |handle_id| handle_id.call(@card.id) }
|
|
270
|
+
store_post_subcards
|
|
271
|
+
true.tap { @virtual = false } # TODO: find a better place for this
|
|
272
|
+
ensure
|
|
273
|
+
@card.handle_subcard_errors
|
|
274
|
+
end
|
|
275
|
+
|
|
276
|
+
# store subcards whose ids we need for this card
|
|
277
|
+
def store_pre_subcards
|
|
278
|
+
@subdirectors.each do |subdir|
|
|
279
|
+
next unless subdir.prior_store
|
|
280
|
+
subdir.catch_up_to_stage :store
|
|
281
|
+
end
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
def store_post_subcards
|
|
285
|
+
@subdirectors.each do |subdir|
|
|
286
|
+
next if subdir.prior_store
|
|
287
|
+
subdir.catch_up_to_stage :store
|
|
288
|
+
end
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# trigger the storage_phase, skip the other phases
|
|
292
|
+
# At this point the :prepare_to_store stage was already executed
|
|
293
|
+
# by the parent director. So the storage phase will only run
|
|
294
|
+
# the :store stage and the :finalize stage
|
|
295
|
+
def trigger_storage_phase_callback
|
|
296
|
+
@stage = stage_index :prepare_to_store
|
|
297
|
+
@card.only_storage_phase = true
|
|
298
|
+
@card.save! validate: false
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
class StageSubdirector < StageDirector
|
|
303
|
+
def initialize card, opts={}
|
|
304
|
+
super card, opts, false
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def delete
|
|
308
|
+
@parent.subdirectors.delete self if @parent
|
|
309
|
+
super
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
end
|
|
313
|
+
end
|