card 1.99.5 → 1.99.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/20140629222005_add_email_cards.rb +1 -1
  4. data/lib/card.rb +13 -23
  5. data/lib/card/act_manager.rb +1 -0
  6. data/lib/card/act_manager/event_delay.rb +10 -5
  7. data/lib/card/act_manager/subdirector_array.rb +2 -0
  8. data/lib/card/auth/current.rb +0 -2
  9. data/lib/card/cache/prepopulate.rb +4 -4
  10. data/lib/card/env.rb +9 -53
  11. data/lib/card/env/location.rb +15 -2
  12. data/lib/card/env/request_assignments.rb +24 -0
  13. data/lib/card/env/serialization.rb +24 -0
  14. data/lib/card/env/slot_options.rb +30 -0
  15. data/lib/card/format/error.rb +6 -1
  16. data/lib/card/mod/loader/set_pattern_loader.rb +5 -1
  17. data/lib/card/model/save_helper.rb +5 -1
  18. data/lib/card/set/event/delayed_event.rb +49 -9
  19. data/lib/card/set/event/options.rb +1 -0
  20. data/lib/card/set/pattern/base.rb +18 -0
  21. data/lib/card/subcards.rb +11 -8
  22. data/lib/card/subcards/add.rb +7 -4
  23. data/lib/card/view/cache/cache_action.rb +1 -1
  24. data/lib/card/view/classy.rb +9 -9
  25. data/lib/card/view/options/voo_api.rb +0 -8
  26. data/mod/account/set/all/account.rb +2 -2
  27. data/mod/account/spec/set/right/account_spec.rb +2 -2
  28. data/mod/account/spec/set/type/signup_spec.rb +1 -1
  29. data/mod/basic_formats/set/all/head.rb +4 -2
  30. data/mod/basic_formats/set/all/rss.rb +1 -1
  31. data/mod/bootstrap/lib/card/lazy_tab.rb +37 -0
  32. data/mod/bootstrap/lib/card/tab.rb +76 -0
  33. data/mod/bootstrap/set/all/bootstrap/dropdown.rb +0 -1
  34. data/mod/bootstrap/set/all/bootstrap/tabs.rb +33 -124
  35. data/mod/bootstrap/set/all/bootstrap/tabs/tab_panel.haml +7 -0
  36. data/mod/carrierwave/set/abstract/attachment.rb +1 -1
  37. data/mod/carrierwave/set/abstract/attachment/upload_cache.rb +1 -1
  38. data/mod/core/lib/card/rule.rb +227 -0
  39. data/mod/core/set/all/actify.rb +16 -2
  40. data/mod/core/set/all/assign_attributes.rb +2 -2
  41. data/mod/core/set/all/cache.rb +4 -0
  42. data/mod/core/set/all/event_conditions.rb +58 -39
  43. data/mod/core/set/all/fetch.rb +1 -1
  44. data/mod/core/set/all/fetch_helper.rb +5 -13
  45. data/mod/core/set/all/initialize.rb +6 -6
  46. data/mod/core/set/all/name_events.rb +2 -3
  47. data/mod/core/set/all/rename.rb +9 -5
  48. data/mod/core/set/all/rules.rb +3 -228
  49. data/mod/core/set/all/tabs.rb +4 -3
  50. data/mod/core/set/all/update_read_rules.rb +1 -1
  51. data/mod/core/set_pattern/08_type_plus_right.rb +1 -2
  52. data/mod/core/spec/set/all/event_conditions_spec.rb +3 -3
  53. data/mod/core/spec/set/all/fetch_helper_spec.rb +6 -0
  54. data/mod/core/spec/set/all/references_spec.rb +9 -0
  55. data/mod/core/spec/set/all/rules_spec.rb +1 -1
  56. data/mod/developer/set/right/debug.rb +13 -14
  57. data/mod/edit/set/all/bridge.rb +7 -7
  58. data/mod/edit/set/all/bridge/tab_visibility.rb +2 -2
  59. data/mod/follow/set/all/follow/followed_by.rb +1 -2
  60. data/mod/follow/set/all/follow/follower_ids.rb +15 -3
  61. data/mod/follow/set/all/notify.rb +1 -5
  62. data/mod/follow/set/type_plus_right/user/follow.rb +4 -7
  63. data/mod/google_analytics/set/all/google_analytics.rb +1 -1
  64. data/mod/history/lib/card/act.rb +1 -1
  65. data/mod/history/set/all/history.rb +23 -17
  66. data/mod/history/set/all/history/acts.rb +0 -4
  67. data/mod/machines/file/all_script_machine_output/file.js +69 -38418
  68. data/mod/machines/file/all_style_machine_output/file.css +1 -1
  69. data/mod/machines/file/script_html5shiv_printshiv_machine_output/file.js +1 -1
  70. data/mod/machines/lib/javascript/decko/filter_items.js.coffee +4 -4
  71. data/mod/machines/lib/javascript/decko/nest_editor_name.js.coffee +1 -1
  72. data/mod/machines/lib/javascript/decko/selectable_filtered_content.js.coffee +12 -0
  73. data/mod/machines/lib/javascript/decko/slotter.js.coffee +1 -1
  74. data/mod/machines/lib/stylesheets/style_cards.scss +1 -1
  75. data/mod/machines/set/abstract/machine/output_update.rb +12 -4
  76. data/mod/machines/set/self/script_decko.rb +1 -1
  77. data/mod/pointer/set/abstract/00_paging_params.rb +1 -3
  78. data/mod/pointer/set/abstract/02_pointer/events.rb +1 -0
  79. data/mod/recaptcha/set/all/recaptcha.rb +1 -1
  80. data/mod/recaptcha/set/self/admin_info.rb +2 -3
  81. data/mod/rules/set/type/set.rb +1 -1
  82. data/mod/search/set/abstract/00_filter_helper.rb +2 -4
  83. data/mod/search/set/abstract/02_search_params.rb +1 -1
  84. data/mod/search/set/abstract/03_filter.rb +2 -0
  85. data/mod/search/set/abstract/03_filter/selectable_filtered_content.haml +2 -0
  86. data/mod/search/template/abstract/search/checkbox_item.haml +2 -3
  87. data/mod/settings/set/right/read.rb +1 -1
  88. data/mod/standard/set/all/rich_html/error.rb +1 -1
  89. data/mod/standard/set/all/rich_html/menu.rb +1 -1
  90. data/mod/standard/set/all/rich_html/show.rb +8 -0
  91. data/mod/tinymce_editor/set/all/reference_editor/nest_editor.rb +6 -8
  92. metadata +13 -5
  93. data/lib/card/tasks/card/seed.rake +0 -0
@@ -0,0 +1,7 @@
1
+ .tabbable.tab-panel{ panel_attr.merge(role: "tabpanel") }
2
+ %ul{ class: "nav nav-#{tab_type}", role: "tablist" }
3
+ - tab_objects.each do |tab|
4
+ = tab.tab_button
5
+ .tab-content
6
+ - tab_objects.each do |tab|
7
+ = tab.send :tab_pane, pane_attr, &block
@@ -20,7 +20,7 @@ event :save_original_filename, :prepare_to_store, on: :save, when: :file_ready_t
20
20
  @current_action.update! comment: original_filename
21
21
  end
22
22
 
23
- event :validate_file_exist, :validate, on: :save do
23
+ event :validate_file_exist, :validate, on: :create do
24
24
  return if empty_ok?
25
25
  if will_be_stored_as == :web
26
26
  errors.add "url is missing" if content.blank?
@@ -54,7 +54,7 @@ end
54
54
 
55
55
  # at some point uploaded files of canceled file card creation
56
56
  # should be deleted. We do this when ever an new file is created.
57
- event :clear_draft_files, :integrate_with_delay, on: :create do
57
+ event :clear_draft_files, :integrate_with_delay, priority: 100, on: :create do
58
58
  Card.delete_tmp_files_of_cached_uploads
59
59
  end
60
60
 
@@ -0,0 +1,227 @@
1
+ class Card
2
+ # Optimized handling of card "rules" (Set+Setting) and preferences.
3
+ module Rule
4
+ RULE_SQL = %(
5
+ SELECT
6
+ rules.id AS rule_id,
7
+ settings.id AS setting_id,
8
+ sets.id AS set_id,
9
+ sets.left_id AS anchor_id,
10
+ sets.right_id AS set_tag_id
11
+ FROM cards rules
12
+ JOIN cards sets ON rules.left_id = sets.id
13
+ JOIN cards settings ON rules.right_id = settings.id
14
+ WHERE sets.type_id = #{SetID}
15
+ AND settings.type_id = #{SettingID}
16
+ AND (settings.codename != 'follow' OR rules.db_content != '')
17
+ AND rules.trash is false
18
+ AND sets.trash is false
19
+ AND settings.trash is false;
20
+ ).freeze
21
+
22
+ # FIXME: "follow" hardcoded above
23
+
24
+ READ_RULE_SQL = %(
25
+ SELECT
26
+ refs.referee_id AS party_id,
27
+ read_rules.id AS read_rule_id
28
+ FROM cards read_rules
29
+ JOIN card_references refs ON refs.referer_id = read_rules.id
30
+ JOIN cards sets ON read_rules.left_id = sets.id
31
+ WHERE read_rules.right_id = #{ReadID}
32
+ AND sets.type_id = #{SetID}
33
+ AND read_rules.trash is false
34
+ AND sets.trash is false;
35
+ ).freeze
36
+
37
+ PREFERENCE_SQL = %(
38
+ SELECT
39
+ preferences.id AS rule_id,
40
+ settings.id AS setting_id,
41
+ sets.id AS set_id,
42
+ sets.left_id AS anchor_id,
43
+ sets.right_id AS set_tag_id,
44
+ users.id AS user_id
45
+ FROM cards preferences
46
+ JOIN cards user_sets ON preferences.left_id = user_sets.id
47
+ JOIN cards settings ON preferences.right_id = settings.id
48
+ JOIN cards users ON user_sets.right_id = users.id
49
+ JOIN cards sets ON user_sets.left_id = sets.id
50
+ WHERE sets.type_id = #{SetID}
51
+ AND settings.type_id = #{SettingID}
52
+ AND (%s or users.codename = 'all')
53
+ AND sets.trash is false
54
+ AND settings.trash is false
55
+ AND users.trash is false
56
+ AND user_sets.trash is false
57
+ AND preferences.trash is false;
58
+ ).freeze
59
+
60
+ class << self
61
+ def global_setting name
62
+ Auth.as_bot do
63
+ (card = Card[name]) && !card.db_content.strip.empty? && card.db_content
64
+ end
65
+ end
66
+
67
+ def toggle val
68
+ val.to_s.strip == "1"
69
+ end
70
+
71
+ def rule_cache
72
+ Card.cache.read("RULES") || populate_rule_caches
73
+ end
74
+
75
+ def read_rule_cache
76
+ Card.cache.read("READRULES") || populate_read_rule_cache
77
+ end
78
+
79
+ # all users that have a user-specific rule for a given rule key
80
+ def user_ids_cache
81
+ Card.cache.read("USER_IDS") || fresh_rule_cache { @user_ids_hash }
82
+ end
83
+
84
+ # all keys of user-specific rules for a given user
85
+ def rule_keys_cache
86
+ Card.cache.read("RULE_KEYS") || fresh_rule_cache { @rule_keys_hash }
87
+ end
88
+
89
+ def clear_rule_cache
90
+ write_rule_cache nil
91
+ write_user_ids_cache nil
92
+ write_rule_keys_cache nil
93
+ end
94
+
95
+ def clear_preference_cache
96
+ # FIXME: too entwined!
97
+ clear_rule_cache
98
+ end
99
+
100
+ def clear_read_rule_cache
101
+ Card.cache.write "READRULES", nil
102
+ end
103
+
104
+ def preference_names user_name, setting_code
105
+ Card.search({ right: { codename: setting_code },
106
+ left: { left: { type_id: SetID },
107
+ right: user_name },
108
+ return: :name },
109
+ "preference cards for user: #{user_name}")
110
+ end
111
+
112
+ def all_user_ids_with_rule_for set_card, setting_code
113
+ cache_key = "#{user_cache_key_base set_card}+#{setting_code}"
114
+ user_ids = user_ids_cache[cache_key] || []
115
+ user_ids.include?(AllID) ? all_user_ids : user_ids
116
+ end
117
+
118
+ private
119
+
120
+ def populate_rule_caches
121
+ @rule_hash = {}
122
+ @user_ids_hash = {}
123
+ @rule_keys_hash = {}
124
+
125
+ interpret_simple_rules
126
+ interpret_preferences
127
+
128
+ write_user_ids_cache @user_ids_hash
129
+ write_rule_keys_cache @rule_keys_hash
130
+ write_rule_cache @rule_hash
131
+ end
132
+
133
+ def populate_read_rule_cache
134
+ hash = rows(READ_RULE_SQL).each_with_object({}) do |row, h|
135
+ party_id = row["party_id"].to_i
136
+ h[party_id] ||= []
137
+ h[party_id] << row["read_rule_id"].to_i
138
+ end
139
+ Card.cache.write "READRULES", hash
140
+ end
141
+
142
+ def rule_cache_key row
143
+ return false unless (setting_code = Card::Codename[row["setting_id"].to_i])
144
+
145
+ anchor_id = row["anchor_id"]
146
+ set_class_id = anchor_id.nil? ? row["set_id"] : row["set_tag_id"]
147
+ return false unless (set_class_code = Card::Codename[set_class_id.to_i])
148
+
149
+ [anchor_id, set_class_code, setting_code].compact.map(&:to_s) * "+"
150
+ end
151
+
152
+ def interpret_simple_rules
153
+ rows(RULE_SQL).each do |row|
154
+ next unless (key = rule_cache_key row)
155
+ @rule_hash[key] = row["rule_id"].to_i
156
+ end
157
+ end
158
+
159
+ def interpret_preferences
160
+ rows(preference_sql).each do |row|
161
+ next unless (key = rule_cache_key row) && (user_id = row["user_id"])
162
+ add_preference_hash_values key, row["rule_id"].to_i, user_id.to_i
163
+ end
164
+ end
165
+
166
+ # User-specific rule use the pattern
167
+ # user+set+setting
168
+ def preference_sql user_id=nil
169
+ PREFERENCE_SQL % user_restriction(user_id)
170
+ end
171
+
172
+ def user_restriction user_id
173
+ if user_id
174
+ "users.id = #{user_id}"
175
+ else
176
+ "users.type_id = #{UserID}"
177
+ end
178
+ end
179
+
180
+ def rows sql
181
+ Card.connection.select_all sql
182
+ end
183
+
184
+ def add_preference_hash_values key, rule_id, user_id
185
+ @rule_hash[preference_key(key, user_id)] = rule_id
186
+ @user_ids_hash[key] ||= []
187
+ @user_ids_hash[key] << user_id
188
+ @rule_keys_hash[user_id] ||= []
189
+ @rule_keys_hash[user_id] << key
190
+ end
191
+
192
+ def user_cache_key_base set_card
193
+ if (l = set_card.left) && (r = set_card.right)
194
+ "#{l.id}+#{Card::Codename[r.id]}"
195
+ else
196
+ Card::Codename[set_card.id].to_s
197
+ end
198
+ end
199
+
200
+ def preference_key key, user_id
201
+ "#{key}+#{user_id}"
202
+ end
203
+
204
+ def fresh_rule_cache
205
+ clear_rule_cache
206
+ rule_cache
207
+ yield
208
+ end
209
+
210
+ def all_user_ids
211
+ Card.where(type_id: UserID).pluck :id
212
+ end
213
+
214
+ def write_rule_cache hash
215
+ Card.cache.write "RULES", hash
216
+ end
217
+
218
+ def write_user_ids_cache hash
219
+ Card.cache.write "USER_IDS", hash
220
+ end
221
+
222
+ def write_rule_keys_cache hash
223
+ Card.cache.write "RULE_KEYS", hash
224
+ end
225
+ end
226
+ end
227
+ end
@@ -1,6 +1,6 @@
1
1
  def act &block
2
2
  @action ||= identify_action
3
- if ActManager.act_card
3
+ if act_card
4
4
  add_to_act &block
5
5
  else
6
6
  start_new_act &block
@@ -16,13 +16,27 @@ end
16
16
 
17
17
  def add_to_act
18
18
  # if only_storage_phase is true then the card is already part of the act
19
- return yield if ActManager.act_card == self || only_storage_phase
19
+ return yield if act_card? || only_storage_phase
20
20
  director.reset_stage
21
21
  director.update_card self
22
22
  self.only_storage_phase = true
23
23
  yield
24
24
  end
25
25
 
26
+ def act_card
27
+ ActManager.act_card
28
+ end
29
+
30
+ def act_card?
31
+ self == act_card
32
+ end
33
+
34
+ def clear_action_specific_attributes
35
+ self.class.action_specific_attributes.each do |attr|
36
+ instance_variable_set "@#{attr}", nil
37
+ end
38
+ end
39
+
26
40
  module ClassMethods
27
41
  def create! opts
28
42
  card = Card.new opts
@@ -33,9 +33,9 @@ end
33
33
  protected
34
34
 
35
35
  module ClassMethods
36
- def assign_or_initialize_by name, attributes, fetch_opts={}
36
+ def assign_or_newish name, attributes, fetch_opts={}
37
37
  if (known_card = Card.fetch(name, fetch_opts))
38
- known_card.refresh.assign_attributes attributes
38
+ known_card.refresh.newish attributes
39
39
  known_card
40
40
  else
41
41
  Card.new attributes.merge(name: name)
@@ -61,6 +61,10 @@ def cache_class_from_type cache_type
61
61
  cache_type ? Card.cache.send(cache_type) : Card.cache
62
62
  end
63
63
 
64
+ def view_cache_clean?
65
+ !db_content_changed?
66
+ end
67
+
64
68
  def view_cache_keys
65
69
  @view_cache_keys ||= hard_read_view_cache_keys || []
66
70
  end
@@ -1,3 +1,6 @@
1
+ Card.action_specific_attributes +=
2
+ %i[skip_hash full_skip_hash trigger_hash full_trigger_hash]
3
+
1
4
  def event_applies? event
2
5
  return unless set_condition_applies? event.set_module, event.opts[:changing]
3
6
 
@@ -6,12 +9,43 @@ def event_applies? event
6
9
  end
7
10
  end
8
11
 
12
+ # force skipping this event for all cards in act
9
13
  def skip_event! *events
10
- forced_skip_events.merge events
14
+ @full_skip_hash = nil
15
+ events.each do |event|
16
+ act_skip_hash[event.to_s] = :force
17
+ end
18
+ end
19
+
20
+ # force skipping this event for this card only
21
+ def skip_event_in_action! *events
22
+ events.each do |event|
23
+ full_skip_hash[event.to_s] = :force
24
+ end
11
25
  end
12
26
 
27
+ # force triggering this event (when it comes up) for all cards in act
13
28
  def trigger_event! *events
14
- forced_trigger_events.merge events
29
+ @full_trigger_hash = nil
30
+ events.each do |event|
31
+ act_trigger_hash[event.to_s] = :force
32
+ end
33
+ end
34
+
35
+ # force triggering this event (when it comes up) for this card only
36
+ def trigger_event_in_action! *events
37
+ events.each do |event|
38
+ full_trigger_hash[event.to_s] = :force
39
+ end
40
+ end
41
+
42
+ # hash form of raw skip setting, eg { "my_event" => true }
43
+ def skip_hash
44
+ @skip_hash ||= hash_with_value skip, true
45
+ end
46
+
47
+ def trigger_hash
48
+ @trigger_hash ||= hash_with_value trigger, true
15
49
  end
16
50
 
17
51
  private
@@ -74,16 +108,18 @@ def when_condition_applies? _event, block
74
108
  end
75
109
  end
76
110
 
111
+ # "applies always means event can run
112
+ # so if skip_condition_applies?, we do NOT skip
77
113
  def skip_condition_applies? event, allowed
78
- return true if never_skip?
114
+ return true unless (val = full_skip_hash[event.name.to_s])
79
115
 
80
- !(standard_skip_event?(event.name, allowed) || force_skip_event?(event.name))
116
+ allowed ? val.blank? : (val != :force)
81
117
  end
82
118
 
83
119
  def trigger_condition_applies? event, required
84
- return true unless required == :required
120
+ return true unless required
85
121
 
86
- trigger_event?(event.name) || force_trigger_event?(event.name)
122
+ full_trigger_hash[event.name.to_s].present?
87
123
  end
88
124
 
89
125
  def single_changed_condition_applies? db_column
@@ -111,49 +147,32 @@ def wrong_action action
111
147
  "on: #{action} method #{method} called on #{@action}"
112
148
  end
113
149
 
114
- def never_skip?
115
- return @never_skip unless @never_skip.nil?
116
-
117
- @never_skip = skip_events.empty? && forced_skip_events.empty?
118
- end
119
-
120
- def standard_skip_event? event, allowed
121
- return false unless allowed == :allowed
122
-
123
- skip_events.include? event.to_s
150
+ def full_skip_hash
151
+ @full_skip_hash ||= act_skip_hash.merge skip_in_action_hash
124
152
  end
125
153
 
126
- def force_skip_event? event
127
- forced_skip_events.include? event
154
+ def act_skip_hash
155
+ (act_card || self).skip_hash
128
156
  end
129
157
 
130
- # holder for skip_event! (with bang) events
131
- def forced_skip_events
132
- @forced_skip_events ||= ::Set.new([])
158
+ def skip_in_action_hash
159
+ hash_with_value skip_in_action, true
133
160
  end
134
161
 
135
- def skip_events
136
- @skip_events ||= begin
137
- events = Array.wrap(skip_event_in_action) + Array.wrap(act_card.skip_event)
138
- ::Set.new events.map(&:to_s)
139
- end
162
+ def full_trigger_hash
163
+ @full_trigger_hash ||= act_trigger_hash.merge trigger_in_action_hash
140
164
  end
141
165
 
142
- # holder for trigger_event! (with bang) events
143
- def forced_trigger_events
144
- @forced_trigger_events ||= ::Set.new([])
166
+ def trigger_in_action_hash
167
+ hash_with_value trigger_in_action, true
145
168
  end
146
169
 
147
- def trigger_event? event
148
- @names_of_triggered_events ||= triggered_events
149
- @names_of_triggered_events.include? event
170
+ def act_trigger_hash
171
+ (act_card || self).trigger_hash
150
172
  end
151
173
 
152
- def triggered_events
153
- events = Array.wrap(trigger_event_in_action) + Array.wrap(act_card.trigger_event)
154
- ::Set.new events.map(&:to_sym)
155
- end
156
-
157
- def force_trigger_event? event
158
- forced_trigger_events.include? event
174
+ def hash_with_value array, value
175
+ Array.wrap(array).each_with_object({}) do |event, hash|
176
+ hash[event.to_s] = value
177
+ end
159
178
  end