card 1.101.3 → 1.101.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/initializers/02_patches/active_record.rb +1 -1
  4. data/config/locales/en.yml +155 -378
  5. data/db/migrate_core_cards/20150202143810_import_bootstrap_layout.rb +1 -1
  6. data/lib/card.rb +15 -2
  7. data/lib/card/auth.rb +5 -2
  8. data/lib/card/auth/current.rb +39 -100
  9. data/lib/card/auth/proxy.rb +36 -16
  10. data/lib/card/auth/token.rb +6 -0
  11. data/lib/card/cache/all.rb +83 -0
  12. data/lib/card/cache/card_class.rb +41 -0
  13. data/lib/card/cache/persistent.rb +3 -34
  14. data/lib/card/cache/persistent_class.rb +28 -0
  15. data/lib/card/codename.rb +1 -1
  16. data/lib/card/content.rb +16 -2
  17. data/lib/card/content/all.rb +59 -0
  18. data/lib/card/director/act_direction.rb +4 -0
  19. data/lib/card/director/all.rb +61 -0
  20. data/lib/card/director/card_class.rb +18 -0
  21. data/lib/card/director/phases.rb +0 -1
  22. data/lib/card/dirty.rb +13 -3
  23. data/lib/card/env/success.rb +14 -14
  24. data/lib/card/env/success/target.rb +9 -11
  25. data/lib/card/error.rb +1 -1
  26. data/lib/card/fetch/all.rb +32 -0
  27. data/lib/card/fetch/card_class.rb +147 -0
  28. data/lib/card/format.rb +1 -1
  29. data/lib/card/format/error.rb +3 -3
  30. data/lib/card/format/nest.rb +1 -1
  31. data/lib/card/format/nest/fetch.rb +1 -1
  32. data/lib/card/lexicon.rb +2 -2
  33. data/lib/card/name/all.rb +8 -0
  34. data/lib/card/name/all/descendants.rb +6 -3
  35. data/lib/card/name/card_class.rb +26 -0
  36. data/lib/card/reference/all.rb +131 -0
  37. data/lib/card/rule/all.rb +75 -0
  38. data/lib/card/set/event/all.rb +95 -0
  39. data/lib/card/set/event/skip_and_trigger.rb +89 -0
  40. data/lib/card/set/pattern/all.rb +63 -0
  41. data/lib/card/subcards/all.rb +103 -0
  42. data/lib/cardio/migration/import.rb +1 -1
  43. data/lib/cardio/utils.rb +5 -3
  44. data/mod/admin/set/self/admin_info.rb +3 -5
  45. data/mod/admin/set/self/trash.rb +2 -2
  46. data/mod/core/set/all/autoname.rb +17 -0
  47. data/mod/core/set/all/codename.rb +2 -2
  48. data/mod/core/set/all/content.rb +52 -97
  49. data/mod/core/set/all/name_events.rb +69 -58
  50. data/mod/core/set/all/reference_events.rb +67 -0
  51. data/mod/core/set/all/states.rb +2 -2
  52. data/mod/core/set/all/subcards.rb +0 -100
  53. data/mod/core/set/all/trash.rb +11 -13
  54. data/mod/core/set/all/type.rb +7 -9
  55. data/mod/core/set/all/utils.rb +3 -0
  56. data/mod/core/set/type/cardtype.rb +3 -3
  57. data/mod/core/set_pattern/06_rule.rb +1 -1
  58. data/mod/core/spec/set/all/{rules2_spec.rb → clean_me_spec.rb} +0 -0
  59. data/mod/core/spec/set/all/name_events_spec.rb +204 -0
  60. metadata +30 -37
  61. data/lib/card/mod_inflector.rb +0 -16
  62. data/lib/card/name/all/class_methods.rb +0 -28
  63. data/mod/core/set/all/actify.rb +0 -68
  64. data/mod/core/set/all/cache.rb +0 -109
  65. data/mod/core/set/all/event_conditions.rb +0 -172
  66. data/mod/core/set/all/fetch.rb +0 -122
  67. data/mod/core/set/all/fetch_helper.rb +0 -35
  68. data/mod/core/set/all/i18n.rb +0 -9
  69. data/mod/core/set/all/pattern.rb +0 -54
  70. data/mod/core/set/all/references.rb +0 -191
  71. data/mod/core/set/all/rename.rb +0 -33
  72. data/mod/core/set/all/rules.rb +0 -81
  73. data/mod/core/spec/set/all/actify_spec.rb +0 -58
  74. data/mod/core/spec/set/all/content_spec.rb +0 -15
  75. data/mod/core/spec/set/all/event_conditions_spec.rb +0 -217
  76. data/mod/core/spec/set/all/fetch_helper_spec.rb +0 -65
  77. data/mod/core/spec/set/all/fetch_spec.rb +0 -338
  78. data/mod/core/spec/set/all/i18n_spec.rb +0 -17
  79. data/mod/core/spec/set/all/pattern_spec.rb +0 -101
  80. data/mod/core/spec/set/all/permissions/reader_rules_spec.rb +0 -166
  81. data/mod/core/spec/set/all/references_spec.rb +0 -62
  82. data/mod/core/spec/set/all/rename_spec.rb +0 -189
  83. data/mod/core/spec/set/all/rules_spec.rb +0 -100
  84. data/mod/core/spec/set/all/subcards_spec.rb +0 -102
@@ -0,0 +1,147 @@
1
+ class Card
2
+ class Fetch
3
+ # = Card#fetch
4
+ #
5
+ # A multipurpose retrieval operator that integrates caching, database lookups,
6
+ # and "virtual" card construction
7
+ module CardClass
8
+ # Look for cards in
9
+ # * cache
10
+ # * database
11
+ # * virtual cards
12
+ #
13
+ # @param args [Integer, String, Card::Name, Symbol, Array]
14
+ # one or more of the three unique identifiers
15
+ # 1. a numeric id (Integer)
16
+ # 2. a name/key (String or Card::Name)
17
+ # 3. a codename (Symbol)
18
+ # If you pass more then one mark or an array of marks they get joined with a '+'.
19
+ # The final argument can be a hash to set the following options
20
+ # :skip_virtual Real cards only
21
+ # :skip_modules Don't load Set modules
22
+ # :look_in_trash Return trashed card objects
23
+ # :local_only Use only local cache for lookup and storing
24
+ # new: { opts for Card#new } Return a new card when not found
25
+ # @return [Card]
26
+ def fetch *args
27
+ Card::Fetch.new(*args)&.retrieve_or_new
28
+ rescue ActiveModel::RangeError => _e
29
+ return Card.new name: "card id out of range: #{f.mark}"
30
+ end
31
+
32
+ # fetch only real (no virtual) cards
33
+ #
34
+ # @param mark - see #fetch
35
+ # @return [Card]
36
+ def [] *mark
37
+ fetch(*mark, skip_virtual: true)
38
+ end
39
+
40
+ # fetch real cards without set modules loaded. Should only be used for
41
+ # simple attributes
42
+ #
43
+ # @example
44
+ # quick_fetch "A", :self, :structure
45
+ #
46
+ # @param mark - see #fetch
47
+ # @return [Card]
48
+ def quick_fetch *mark
49
+ fetch(*mark, skip_virtual: true, skip_modules: true)
50
+ end
51
+
52
+ # @return [Card]
53
+ def fetch_from_cast cast
54
+ fetch_args = cast[:id] ? [cast[:id].to_i] : [cast[:name], { new: cast }]
55
+ fetch(*fetch_args)
56
+ end
57
+
58
+ #----------------------------------------------------------------------
59
+ # ATTRIBUTE FETCHING
60
+ # The following methods optimize fetching of specific attributes
61
+
62
+ def id cardish
63
+ case cardish
64
+ when Integer then cardish
65
+ when Card then cardish.id
66
+ when Symbol then Card::Codename.id cardish
67
+ else fetch_id cardish
68
+ end
69
+ end
70
+
71
+ # @param mark_parts - see #fetch
72
+ # @return [Integer]
73
+ def fetch_id *mark_parts
74
+ mark = Card::Fetch.new(*mark_parts)&.mark
75
+ mark.is_a?(Integer) ? mark : quick_fetch(mark.to_s)&.id
76
+ end
77
+
78
+ # @param mark - see #fetch
79
+ # @return [Card::Name]
80
+ def fetch_name *mark, &block
81
+ if (card = quick_fetch(*mark))
82
+ card.name
83
+ elsif block_given?
84
+ yield.to_name
85
+ end
86
+ rescue => error
87
+ rescue_fetch_name error, &block
88
+ end
89
+
90
+ # @param mark - see #fetch
91
+ # @return [Integer]
92
+ def fetch_type_id *mark
93
+ fetch(*mark, skip_modules: true)&.type_id
94
+ end
95
+
96
+ # a fetch method to support the needs of the card controller.
97
+ # should be in Decko?
98
+ def controller_fetch args
99
+ card_opts = controller_fetch_opts args
100
+ if args[:action] == "create"
101
+ # FIXME: we currently need a "new" card to catch duplicates
102
+ # (otherwise save will just act like a normal update)
103
+ # We may need a "#create" instance method to handle this checking?
104
+ Card.new card_opts
105
+ else
106
+ standard_controller_fetch args, card_opts
107
+ end
108
+ end
109
+
110
+ private
111
+
112
+ def standard_controller_fetch args, card_opts
113
+ mark = args[:mark] || card_opts[:name]
114
+ card = Card.fetch mark, skip_modules: true,
115
+ look_in_trash: args[:look_in_trash],
116
+ new: card_opts
117
+ card.assign_attributes card_opts if args[:assign] && card&.real?
118
+ card&.include_set_modules
119
+ card
120
+ end
121
+
122
+ def controller_fetch_opts args
123
+ opts = Env.hash args[:card]
124
+ opts[:type] ||= args[:type] if args[:type]
125
+ # for /new/:type shortcut. we should handle in routing and deprecate this
126
+ opts[:name] ||= Name.url_key_to_standard args[:mark]
127
+ opts
128
+ end
129
+
130
+ def rescue_fetch_name error, &block
131
+ if rescued_fetch_name_to_name? error, &block
132
+ yield.to_name
133
+ elsif error.is_a? ActiveModel::RangeError
134
+ nil
135
+ else
136
+ raise error
137
+ end
138
+ end
139
+
140
+ def rescued_fetch_name_to_name? error
141
+ return unless block_given?
142
+
143
+ error.is_a?(ActiveModel::RangeError) || error.is_a?(Error::CodenameNotFound)
144
+ end
145
+ end
146
+ end
147
+ end
data/lib/card/format.rb CHANGED
@@ -47,7 +47,7 @@ class Card
47
47
  def require_card_to_initialize!
48
48
  return if @card
49
49
 
50
- raise Card::Error, Cardio.t(:exception_init_without_card)
50
+ raise Card::Error, Cardio.t(:lib_exception_init_without_card)
51
51
  end
52
52
 
53
53
  def include_set_format_modules
@@ -29,7 +29,7 @@ class Card
29
29
  end
30
30
 
31
31
  def monitor_depth
32
- raise Card::Error::UserError, tr(:too_deep) if depth >= Card.config.max_depth
32
+ raise Card::Error::UserError, t(:format_too_deep) if depth >= Card.config.max_depth
33
33
  yield
34
34
  end
35
35
 
@@ -42,7 +42,7 @@ class Card
42
42
  if card&.name.present?
43
43
  safe_name
44
44
  else
45
- Cardio.tr :no_cardname
45
+ Cardio.t :lib_no_cardname
46
46
  end
47
47
  end
48
48
 
@@ -71,7 +71,7 @@ class Card
71
71
  if exception.is_a? Card::Error::UserError
72
72
  exception.message
73
73
  else
74
- tr :error_rendering, cardname: error_cardname(exception), view: view
74
+ t :lib_error_rendering, cardname: error_cardname(exception), view: view
75
75
  end
76
76
  end
77
77
  end
@@ -2,7 +2,7 @@ class Card
2
2
  class Format
3
3
  # processing nests
4
4
  class Nest
5
- include Fetch
5
+ include Nest::Fetch
6
6
 
7
7
  attr_accessor :format, :card, :view, :view_opts, :format_opts
8
8
  def initialize format, cardish, view_opts={}, format_opts={}
@@ -24,7 +24,7 @@ class Card
24
24
  end
25
25
 
26
26
  def not_found_codename_error codename
27
- Cardio.tr :exception_unknown_codename, codename: codename
27
+ Cardio.t :lib_exception_unknown_codename, codename: codename
28
28
  end
29
29
 
30
30
  def new_card cardish
data/lib/card/lexicon.rb CHANGED
@@ -36,12 +36,12 @@ class Card
36
36
 
37
37
  def update card
38
38
  add card
39
- cache.delete cache_key(card.old_lex)
39
+ cache.delete cache_key(card.lex_before_act)
40
40
  end
41
41
 
42
42
  # def delete card
43
43
  # cache.delete card.id.to_s
44
- # cache.delete cache_key(card.old_lex)
44
+ # cache.delete cache_key(card.lex_before_act)
45
45
  # end
46
46
 
47
47
  def lex_to_name lex
data/lib/card/name/all.rb CHANGED
@@ -35,6 +35,10 @@ class Card
35
35
  end
36
36
  end
37
37
 
38
+ def lex
39
+ simple? ? name : [left_id, right_id]
40
+ end
41
+
38
42
  def autoname name
39
43
  if Card.exists?(name) || Director.include?(name)
40
44
  autoname name.next
@@ -64,6 +68,10 @@ class Card
64
68
  @key
65
69
  end
66
70
 
71
+ def field tag, opts={}
72
+ Card.fetch name.field(tag), opts
73
+ end
74
+
67
75
  private
68
76
 
69
77
  def assign_side_ids
@@ -19,9 +19,12 @@ class Card
19
19
  end
20
20
 
21
21
  def each_child
22
- child_ids.each do |id|
23
- (child = Card[id]) && yield(child)
24
- # check should not be needed (remove after fixing data problems)
22
+ return unless id
23
+
24
+ Card.where(
25
+ "(left_id = #{id} or right_id = #{id}) and trash is false"
26
+ ).each do |child|
27
+ yield child
25
28
  end
26
29
  end
27
30
 
@@ -0,0 +1,26 @@
1
+ class Card
2
+ class Name
3
+ # Name-related Card class methods
4
+ module CardClass
5
+ def rename! oldname, newname
6
+ Card[oldname].update! name: newname, update_referers: true
7
+ end
8
+
9
+ def uniquify_name name, rename=:new
10
+ return name unless Card.exists? name
11
+ uniq_name = generate_alternative_name name
12
+ return uniq_name unless rename == :old
13
+ rename!(name, uniq_name)
14
+ name
15
+ end
16
+
17
+ private
18
+
19
+ def generate_alternative_name name
20
+ uniq_name = "#{name} 1"
21
+ uniq_name.next! while Card.exists?(uniq_name)
22
+ uniq_name
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,131 @@
1
+ class Card
2
+ class Reference < ApplicationRecord
3
+ module All
4
+ # frozen_string_literal: true
5
+
6
+ # Cards can refer to other cards in their content, eg via links and nests.
7
+ # The card that refers is the "referer", the card that is referred to is
8
+ # the "referee". The reference itself has its own class (Card::Reference),
9
+ # which handles id-based reference tracking.
10
+
11
+ PARTIAL_REF_CODE = "P".freeze
12
+
13
+ # cards that refer to self
14
+ def referers
15
+ referer_cards_from_references references_in
16
+ end
17
+
18
+ # cards that include self
19
+ def nesters
20
+ referer_cards_from_references references_in.where(ref_type: "I")
21
+ end
22
+
23
+ def referer_cards_from_references references
24
+ references.map(&:referer_id).uniq.map(&Card.method(:fetch)).compact
25
+ end
26
+
27
+ # cards that self refers to
28
+ def referees
29
+ referees_from_references references_out
30
+ end
31
+
32
+ # cards that self includes
33
+ def nestees
34
+ referees_from_references references_out.where(ref_type: "I")
35
+ end
36
+
37
+ def referees_from_references references
38
+ references.map(&:referee_key).uniq.map { |key| Card.fetch key, new: {} }
39
+ end
40
+
41
+ # cards that refer to self by name
42
+ # (finds cards not yet linked by id)
43
+ def name_referers
44
+ Card.joins(:references_out).where card_references: { referee_key: key }
45
+ end
46
+
47
+ # delete old references from this card's content, create new ones
48
+ def update_references_out
49
+ delete_references_out
50
+ create_references_out
51
+ end
52
+
53
+ # interpret references from this card's content and
54
+ # insert entries in reference table
55
+ def create_references_out
56
+ ref_hash = {}
57
+ each_reference_out do |referee_name, ref_type|
58
+ interpret_reference ref_hash, referee_name, ref_type
59
+ end
60
+ return if ref_hash.empty?
61
+ Reference.mass_insert reference_values_array(ref_hash)
62
+ end
63
+
64
+ # delete references from this card
65
+ def delete_references_out
66
+ raise "id required to delete references" if id.nil?
67
+ Reference.where(referer_id: id).delete_all
68
+ end
69
+
70
+ private
71
+
72
+ def with_normalized_referee referee_name
73
+ return unless referee_name # eg commented nest has no referee_name
74
+ referee_name = referee_name.to_name
75
+ referee_key = referee_name.key
76
+ return if referee_key == key # don't create self reference
77
+ yield referee_name, referee_key, Lexicon.id(referee_name)
78
+ end
79
+
80
+ # interpretation phase helps to prevent duplicate references
81
+ # results in hash like:
82
+ # { referee1_key: [referee1_id, referee1_type2],
83
+ # referee2_key...
84
+ # }
85
+ def interpret_reference ref_hash, raw_referee_name, ref_type
86
+ with_normalized_referee raw_referee_name do |name, key, id|
87
+ ref_hash[key] ||= [id]
88
+ ref_hash[key] << ref_type
89
+ interpret_partial_references ref_hash, name unless id
90
+ end
91
+ end
92
+
93
+ # translate interpreted reference hash into values array,
94
+ # removing duplicate and unnecessary ref_types
95
+ def reference_values_array ref_hash
96
+ [].tap do |values|
97
+ ref_hash.each do |referee_key, hash_val|
98
+ referee_id = hash_val.shift || "null"
99
+ each_reference_type hash_val.uniq do |ref_type|
100
+ values << [id, referee_id, "'#{referee_key}'", "'#{ref_type}'"]
101
+ end
102
+ end
103
+ end
104
+ end
105
+
106
+ def each_reference_type ref_types
107
+ ref_types.delete PARTIAL_REF_CODE if ref_types.size > 1
108
+ # partial references are not necessary if there are explicit references
109
+ ref_types.each { |ref_type| yield ref_type }
110
+ end
111
+
112
+ # invokes the given block for each reference in content with
113
+ # the reference name and reference type
114
+ def each_reference_out
115
+ content_object.find_chunks(:Reference).each do |chunk|
116
+ yield chunk.referee_name, chunk.reference_code
117
+ end
118
+ end
119
+
120
+ # Partial references are needed to track references to virtual cards.
121
+ # For example a link to virual card [[A+*self]] won't have a referee_id,
122
+ # but when A's name is changed we have to find and update that link.
123
+ def interpret_partial_references ref_hash, referee_name
124
+ return if referee_name.simple?
125
+ [referee_name.left, referee_name.right].each do |sidename|
126
+ interpret_reference ref_hash, sidename, PARTIAL_REF_CODE
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
@@ -0,0 +1,75 @@
1
+ class Card
2
+ module Rule
3
+ # rule-related Card instance methods
4
+ module All
5
+ def rule setting_code
6
+ rule_card(setting_code, skip_modules: true)&.db_content
7
+ end
8
+
9
+ def rule_card setting_code, options={}
10
+ Card.fetch rule_card_id(setting_code), options
11
+ end
12
+
13
+ def rule_card_id setting_code
14
+ rule_id_lookup Card::Rule.rule_cache, setting_code
15
+ end
16
+
17
+ def preference setting_code, user=nil
18
+ preference_card(setting_code, user, skip_modules: true)&.db_content
19
+ end
20
+
21
+ def preference_card setting_code, user=nil, options={}
22
+ Card.fetch preference_card_id(setting_code, user), options
23
+ end
24
+
25
+ def preference_card_id setting_code, user=nil
26
+ return unless (user_id = preference_user_id user)
27
+ rule_id_lookup Card::Rule.preference_cache,
28
+ "#{setting_code}+#{user_id}",
29
+ "#{setting_code}+#{AllID}"
30
+ end
31
+
32
+ def rule?
33
+ standard_rule? || preference?
34
+ end
35
+
36
+ def standard_rule?
37
+ (Card.fetch_type_id(name.right) == SettingID) &&
38
+ (Card.fetch_type_id(name.left) == SetID)
39
+ end
40
+
41
+ def preference?
42
+ name.parts.length > 2 &&
43
+ (Card.fetch_type_id(name.right) == SettingID) &&
44
+ (Card.fetch_type_id(name[0..-3]) == SetID) &&
45
+ valid_preferer?
46
+ end
47
+
48
+ private
49
+
50
+ def valid_preferer?
51
+ preferer = self[-2, skip_modules: true]
52
+ (preferer.type_id == UserID) || (preferer.codename == :all)
53
+ end
54
+
55
+ def preference_user_id user
56
+ case user
57
+ when Integer then user
58
+ when Card then user.id
59
+ when nil then Auth.current_id
60
+ else
61
+ raise Card::ServerError, "invalid preference user"
62
+ end
63
+ end
64
+
65
+ def rule_id_lookup lookup_hash, cache_suffix, fallback_suffix=nil
66
+ rule_set_keys.each do |rule_set_key|
67
+ rule_id = lookup_hash["#{rule_set_key}+#{cache_suffix}"]
68
+ rule_id ||= fallback_suffix && lookup_hash["#{rule_set_key}+#{fallback_suffix}"]
69
+ return rule_id if rule_id
70
+ end
71
+ nil
72
+ end
73
+ end
74
+ end
75
+ end