card 1.20.2 → 1.20.3

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.
Files changed (112) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +3 -1
  4. data/config/initializers/01_core_extensions/array.rb +1 -1
  5. data/config/initializers/01_core_extensions/module.rb +1 -1
  6. data/config/initializers/02_patches/active_record.rb +66 -0
  7. data/config/initializers/patches.rb +4 -0
  8. data/db/migrate_core_cards/20170314175313_add_notification_event_card.rb +21 -0
  9. data/db/seed/new/card_actions.yml +723 -475
  10. data/db/seed/new/card_acts.yml +45 -45
  11. data/db/seed/new/card_changes.yml +2306 -1675
  12. data/db/seed/new/card_references.yml +389 -116
  13. data/db/seed/new/cards.yml +2537 -2067
  14. data/db/seed/test/fixtures/card_actions.yml +1709 -1445
  15. data/db/seed/test/fixtures/card_acts.yml +302 -290
  16. data/db/seed/test/fixtures/card_changes.yml +5494 -4818
  17. data/db/seed/test/fixtures/card_references.yml +1137 -794
  18. data/db/seed/test/fixtures/cards.yml +3631 -3120
  19. data/db/version_core_cards.txt +1 -1
  20. data/lib/card/auth/current.rb +21 -0
  21. data/lib/card/env.rb +7 -2
  22. data/lib/card/env/success.rb +13 -3
  23. data/lib/card/format/render.rb +13 -4
  24. data/lib/card/migration.rb +4 -6
  25. data/lib/card/mod/loader.rb +8 -0
  26. data/lib/card/model/save_helper.rb +45 -0
  27. data/lib/card/name/view_name.rb +8 -6
  28. data/lib/card/query/join.rb +4 -2
  29. data/lib/card/query/sorting.rb +26 -22
  30. data/lib/card/reference.rb +2 -2
  31. data/lib/card/set/advanced_api.rb +31 -6
  32. data/lib/card/set/event.rb +16 -8
  33. data/lib/card/set/format.rb +15 -0
  34. data/lib/card/set/format/haml_views.rb +78 -0
  35. data/lib/card/set/loader.rb +3 -2
  36. data/lib/cardio.rb +17 -1
  37. data/mod/Modfile +2 -1
  38. data/mod/account/spec/set/all/account_spec.rb +1 -1
  39. data/mod/basic_formats/set/all/all_css.rb +4 -5
  40. data/mod/bootstrap/set/all/bootstrap/navbar.rb +6 -0
  41. data/mod/bootstrap/set/all/bootstrap/tabs.rb +13 -6
  42. data/mod/carrierwave/set/abstract/attachment/upload_cache.rb +6 -0
  43. data/mod/core/set/all/assign_attributes.rb +3 -0
  44. data/mod/core/set/all/fetch.rb +3 -3
  45. data/mod/core/spec/set/all/collection_spec.rb +5 -3
  46. data/mod/history/lib/card/change.rb +2 -2
  47. data/mod/machines/file/all_script_machine_output/file.js +37 -121
  48. data/mod/machines/file/all_style_machine_output/file.css +4 -4
  49. data/mod/machines/lib/javascript/wagn.js.coffee +4 -0
  50. data/mod/machines/lib/javascript/wagn_mod.js.coffee +0 -2
  51. data/mod/machines/set/type/css.rb +6 -0
  52. data/mod/{email → notifications}/format/email_html_format.rb +0 -0
  53. data/mod/{email → notifications}/format/email_text_format.rb +0 -0
  54. data/mod/{email → notifications}/lib/card/follow_option.rb +0 -0
  55. data/mod/{email → notifications}/set/abstract/test_context.rb +0 -0
  56. data/mod/{email → notifications}/set/all/email_html.rb +0 -0
  57. data/mod/{email → notifications}/set/all/email_text.rb +0 -0
  58. data/mod/{email → notifications}/set/all/follow.rb +0 -0
  59. data/mod/notifications/set/all/observer.rb +22 -0
  60. data/mod/{email/set/all/notify.rb → notifications/set/all/send_notifications.rb} +0 -0
  61. data/mod/notifications/set/all/show_notifications.rb +7 -0
  62. data/mod/{email → notifications}/set/right/bcc.rb +0 -0
  63. data/mod/{email → notifications}/set/right/cc.rb +0 -0
  64. data/mod/{email → notifications}/set/right/follow.rb +0 -0
  65. data/mod/{email → notifications}/set/right/follow_fields.rb +0 -0
  66. data/mod/{email → notifications}/set/right/followers.rb +0 -0
  67. data/mod/{email → notifications}/set/right/following.rb +0 -0
  68. data/mod/{email → notifications}/set/right/from.rb +0 -0
  69. data/mod/{email → notifications}/set/right/html_message.rb +0 -0
  70. data/mod/{email → notifications}/set/right/subject.rb +0 -0
  71. data/mod/{email → notifications}/set/right/text_message.rb +0 -0
  72. data/mod/{email → notifications}/set/right/to.rb +0 -0
  73. data/mod/{email → notifications}/set/self/always.rb +0 -0
  74. data/mod/{email → notifications}/set/self/created.rb +0 -0
  75. data/mod/{email → notifications}/set/self/edited.rb +0 -0
  76. data/mod/{email → notifications}/set/self/follow.rb +0 -0
  77. data/mod/{email → notifications}/set/self/follow_defaults.rb +0 -0
  78. data/mod/{email → notifications}/set/self/never.rb +0 -0
  79. data/mod/{email → notifications}/set/type/email_template.rb +0 -0
  80. data/mod/{email → notifications}/set/type/email_template/email_config.rb +0 -0
  81. data/mod/notifications/set/type/notification_template.rb +23 -0
  82. data/mod/{email → notifications}/set/type_plus_right/user/follow.rb +0 -0
  83. data/mod/{email → notifications}/spec/set/all/follow_spec.rb +14 -5
  84. data/mod/{email → notifications}/spec/set/all/notify_spec.rb +1 -1
  85. data/mod/{email → notifications}/spec/set/all/observer_spec.rb +1 -1
  86. data/mod/{email → notifications}/spec/set/right/followers_spec.rb +0 -0
  87. data/mod/{email → notifications}/spec/set/right/following_spec.rb +0 -0
  88. data/mod/{email → notifications}/spec/set/self/follow_defaults_spec.rb +0 -0
  89. data/mod/notifications/spec/set/type/notification_template_spec.rb +58 -0
  90. data/mod/{standard/set/abstract/search/paging.rb → pointer/set/abstract/00_paging.rb} +10 -1
  91. data/mod/{standard/set/abstract/search/paging → pointer/set/abstract/00_paging}/paging_links.rb +0 -0
  92. data/mod/pointer/set/abstract/01_pointer.rb +13 -1
  93. data/mod/pointer/spec/set/type/pointer_spec.rb +7 -0
  94. data/mod/standard/set/abstract/01_search_params.rb +4 -0
  95. data/mod/standard/set/abstract/search.rb +1 -0
  96. data/mod/standard/set/abstract/wql_search.rb +6 -4
  97. data/mod/standard/set/all/rich_html/toolbar.rb +31 -16
  98. data/mod/standard/set/all/rich_html/wrapper.rb +3 -1
  99. data/mod/standard/set/self/search.rb +28 -8
  100. data/mod/standard/set/type/search_type.rb +10 -8
  101. data/mod/standard/spec/set/all/rich_html/editing_spec.rb +2 -1
  102. data/mod/standard/spec/set/all/rich_html/form_spec.rb +2 -2
  103. data/mod/standard/spec/set/self/search_spec.rb +8 -1
  104. data/mod/standard/spec/set/type/phrase_spec.rb +2 -1
  105. data/mod/twitter/Gemfile +3 -0
  106. data/mod/twitter/db/migrate_cards/20170305112346_add_twitter_cards.rb +30 -0
  107. data/mod/twitter/set/type/twitter_template.rb +22 -0
  108. data/spec/lib/card/query/sorting_spec.rb +68 -0
  109. data/spec/lib/card/query_spec.rb +0 -65
  110. metadata +78 -40
  111. data/mod/email/set/all/observer.rb +0 -26
  112. data/mod/standard/spec/set/all/email_html_spec.rb +0 -15
@@ -1 +1 @@
1
- 20170209132834
1
+ 20170314175313
@@ -49,6 +49,27 @@ class Card
49
49
  end
50
50
  end
51
51
 
52
+ def serialize
53
+ { as_id: as_id, current_id: current_id }
54
+ end
55
+
56
+ # @param auth_data [Integer|Hash] user id or a hash
57
+ # @opts auth_data [Integer] current_id
58
+ # @opts auth_data [Integer] as_id
59
+ def with auth_data
60
+ auth_data = { current_id: auth_data } if auth_data.is_a?(Integer)
61
+ raise ArgumentError unless auth_data.is_a? Hash
62
+
63
+ tmp_current = current_id
64
+ tmp_as_id = as_id
65
+ @current_id = auth_data[:current_id]
66
+ @as_id = auth_data[:as_id] if auth_data[:as_id]
67
+ yield
68
+ ensure
69
+ @current_id = tmp_current
70
+ @as_id = tmp_as_id
71
+ end
72
+
52
73
  # get session object from Env
53
74
  # return [Session]
54
75
  def session
@@ -64,9 +64,14 @@ class Card
64
64
  @env.select { |k, _v| SERIALIZABLE_ATTRIBUTES.include?(k) }
65
65
  end
66
66
 
67
- def deserialize! data
67
+ # @param serialized_env [Hash]
68
+ def with serialized_env
69
+ tmp_env = serialize if @env
68
70
  @env ||= {}
69
- @env.update data
71
+ @env.update serialized_env
72
+ yield
73
+ ensure
74
+ @env.update tmp_env if tmp_env
70
75
  end
71
76
 
72
77
  private
@@ -43,7 +43,9 @@ class Card
43
43
  end
44
44
 
45
45
  def id= id
46
- self.mark = id # for backwards compatibility use mark here: id was often used for the card name
46
+ # for backwards compatibility use mark here.
47
+ # id was often used for the card name
48
+ self.mark = id
47
49
  end
48
50
 
49
51
  def type= type
@@ -63,7 +65,7 @@ class Card
63
65
  case value
64
66
  when "" then ""
65
67
  when "*previous", :previous then :previous
66
- when /^(http|\/)/ then value
68
+ when %r{^(http|/)} then value
67
69
  when /^TEXT:\s*(.+)/ then Regexp.last_match(1)
68
70
  when /^REDIRECT:\s*(.+)/
69
71
  @redirect = true
@@ -89,7 +91,9 @@ class Card
89
91
  end
90
92
 
91
93
  def target name_context=@name_context
92
- card(name_context) || (@target == :previous ? Card::Env.previous_location : @target) || Card.fetch(name_context)
94
+ card(name_context) ||
95
+ (@target == :previous ? Card::Env.previous_location : @target) ||
96
+ Card.fetch(name_context)
93
97
  end
94
98
 
95
99
  def []= key, value
@@ -112,6 +116,12 @@ class Card
112
116
  end
113
117
  end
114
118
 
119
+ def flash message=nil
120
+ @params[:flash] ||= []
121
+ @params[:flash] << message if message
122
+ @params[:flash]
123
+ end
124
+
115
125
  def params
116
126
  @params.marshal_dump
117
127
  end
@@ -113,10 +113,19 @@ class Card
113
113
  end
114
114
 
115
115
  def view_method view
116
- method "_view_#{view}"
117
- rescue
118
- voo.unsupported_view = view
119
- method "_view_unsupported_view"
116
+ unless supports_view? view
117
+ voo.unsupported_view = view
118
+ view = :unsupported_view
119
+ end
120
+ method view_method_name(view)
121
+ end
122
+
123
+ def supports_view? view
124
+ respond_to? view_method_name(view)
125
+ end
126
+
127
+ def view_method_name view
128
+ "_view_#{view}"
120
129
  end
121
130
 
122
131
  def current_view view
@@ -62,12 +62,10 @@ class Card::Migration < ActiveRecord::Migration
62
62
  Card::Cache.reset_all
63
63
  Cardio.schema_mode "" do
64
64
  Card::Auth.as_bot do
65
- ActiveRecord::Base.transaction do
66
- begin
67
- yield
68
- ensure
69
- Card::Cache.reset_all
70
- end
65
+ begin
66
+ yield
67
+ ensure
68
+ Card::Cache.reset_all
71
69
  end
72
70
  end
73
71
  end
@@ -18,6 +18,7 @@ class Card
18
18
  module Loader
19
19
  class << self
20
20
  def load_mods
21
+ load_initializers
21
22
  load_set_patterns
22
23
  load_formats
23
24
  load_sets
@@ -89,6 +90,13 @@ class Card
89
90
  files.flatten
90
91
  end
91
92
 
93
+ def load_initializers
94
+ Card.config.paths["mod/config/initializers"].existent
95
+ .sort.each do |initializer|
96
+ load initializer
97
+ end
98
+ end
99
+
92
100
  def load_set_patterns
93
101
  generate_set_pattern_tmp_files if rewrite_tmp_files?
94
102
  load_dir Card.paths["tmp/set_pattern"].first
@@ -9,6 +9,14 @@ class Card
9
9
  # All !-methods in this module rename existing cards
10
10
  # to resolve name conflicts)
11
11
  module SaveHelper
12
+ def as_user user_name
13
+ current = Card::Auth.current_id
14
+ Card::Auth.current_id = Card.fetch_id user_name
15
+ result = yield
16
+ Card::Auth.current_id = current
17
+ result
18
+ end
19
+
12
20
  def create_card name_or_args, content_or_args=nil
13
21
  args = standardize_args name_or_args, content_or_args
14
22
  resolve_name_conflict args
@@ -75,6 +83,43 @@ class Card
75
83
  end
76
84
  end
77
85
 
86
+
87
+ # Creates or updates a trait card with codename and right rules.
88
+ # Content for rules that are pointer cards by default
89
+ # is converted to pointer format.
90
+ # @example
91
+ # ensure_trait "*a_or_b", :a_or_b,
92
+ # default: { type_id: Card::PointerID },
93
+ # options: ["A", "B"],
94
+ # input: "radio"
95
+ def ensure_trait name, codename, args={}
96
+ ensure_card name, codename: codename
97
+ args.each do |setting, value|
98
+ ensure_trait_rule name, setting, value
99
+ end
100
+ end
101
+
102
+ def ensure_trait_rule trait, setting, value
103
+ validate_setting setting
104
+ card_args = normalize_trait_rule_args setting, value
105
+ ensure_card [trait, :right, setting], card_args
106
+ end
107
+
108
+ def validate_setting setting
109
+ unless Card::Codename[setting] &&
110
+ Card.fetch_type_id(setting) == SettingID
111
+ raise ArgumentError, "not a valid setting: #{setting}"
112
+ end
113
+ end
114
+
115
+ def normalize_trait_rule_args setting, value
116
+ return value if value.is_a? Hash
117
+ if Card.fetch_type_id([setting, :right, :default]) == PointerID
118
+ value = Array(value).to_pointer_content
119
+ end
120
+ { content: value }
121
+ end
122
+
78
123
  # if card with same name exists move it out of the way
79
124
  def create_card! name_or_args, content_or_args=nil
80
125
  args = standardize_args name_or_args, content_or_args
@@ -12,7 +12,7 @@ class Card
12
12
  def new obj
13
13
  return obj if self.class === obj
14
14
  str = Array === obj ? obj * joint : obj.to_s
15
- if known_name = @@name2viewnameobject[str]
15
+ if (known_name = @@name2viewnameobject[str])
16
16
  known_name
17
17
  else
18
18
  super str.strip
@@ -23,13 +23,14 @@ class Card
23
23
  def initialize str
24
24
  @s = str.to_s.strip
25
25
  @s = @s.encode("UTF-8") if RUBYENCODING
26
- @key = if @s.index(self.class.joint)
27
- @parts = @s.split(/\s*#{JOINT_RE}\s*/)
26
+ @key =
27
+ if @s.index(self.class.joint)
28
+ @parts = @s.split(/\s*#{JOINT_RE}\s*/)
28
29
  @parts << "" if @s[-1, 1] == self.class.joint
29
30
  @simple = false
30
31
  @parts.map { |p| p.to_name.key } * self.class.joint
31
- else
32
- @parts = [str]
32
+ else
33
+ @parts = [str]
33
34
  @simple = true
34
35
  str.empty? ? "" : simple_key
35
36
  end
@@ -37,7 +38,8 @@ class Card
37
38
  end
38
39
 
39
40
  def simple_key
40
- decoded.underscore.gsub(/[^#{OK4KEY_RE}]+/, "_").split(/_+/).reject(&:empty?) * "_"
41
+ decoded.underscore.gsub(/[^#{OK4KEY_RE}]+/, "_")
42
+ .split(/_+/).reject(&:empty?) * "_"
41
43
  end
42
44
 
43
45
  def to_viewname
@@ -8,6 +8,7 @@ class Card
8
8
  :from_field, :to_field,
9
9
  :superjoin, :subjoins
10
10
 
11
+ # documentation??? -pk
11
12
  def initialize opts={}
12
13
  from_and_to opts
13
14
  opts.each do |key, value|
@@ -15,8 +16,9 @@ class Card
15
16
  end
16
17
  @from_field ||= :id
17
18
  @to_field ||= :id
18
- @conditions = []
19
- @subjoins = []
19
+
20
+ @conditions = Array @conditions
21
+ @subjoins = Array @subjoins
20
22
  if @from.is_a? Join
21
23
  @superjoin = @from
22
24
  @superjoin.subjoins << self
@@ -22,30 +22,34 @@ class Card
22
22
 
23
23
  # EXPERIMENTAL!
24
24
  def sort_by_count val, item
25
- if item == "referred_to"
26
- @mods[:sort] = "coalesce(count,0)" # needed for postgres
27
- cs = Query.new(
28
- return: "coalesce(count(*), 0) as count",
29
- group: "sort_join_field",
30
- superquery: self
31
- )
32
- subselect = Query.new val.merge(return: "id", superquery: self)
33
- cs.add_condition "referer_id in (#{subselect.sql})"
34
- # FIXME: - SQL generated before SQL phase
35
- cs.joins << Join.new(
36
- from: cs,
37
- to: %w(card_references wr referee_id)
38
- )
39
- cs.mods[:sort_join_field] = "#{cs.table_alias}.id as sort_join_field"
40
- # HACK!
41
-
42
- joins << Join.new(
43
- from: self,
44
- to: [cs, "srtbl", "sort_join_field"]
45
- )
46
- else
25
+ method_name = "sort_by_count_#{item}"
26
+ unless respond_to?(method_name)
47
27
  raise Card::Error::BadQuery, "count with item: #{item} not yet implemented"
48
28
  end
29
+ send method_name, val
30
+ end
31
+
32
+ def sort_by_count_referred_to val
33
+ @mods[:sort] = "coalesce(count,0)" # needed for postgres
34
+ cs = Query.new(
35
+ return: "coalesce(count(*), 0) as count",
36
+ group: "sort_join_field",
37
+ superquery: self
38
+ )
39
+ subselect = Query.new val.merge(return: "id", superquery: self)
40
+ cs.add_condition "referer_id in (#{subselect.sql})"
41
+ # FIXME: - SQL generated before SQL phase
42
+ cs.joins << Join.new(
43
+ from: cs,
44
+ to: %w(card_references wr referee_id)
45
+ )
46
+ cs.mods[:sort_join_field] = "#{cs.table_alias}.id as sort_join_field"
47
+ # HACK!
48
+
49
+ joins << Join.new(
50
+ from: self,
51
+ to: [cs, "srtbl", "sort_join_field"]
52
+ )
49
53
  end
50
54
  end
51
55
  end
@@ -41,10 +41,10 @@ class Card
41
41
  "LEFT JOIN cards ON card_references.referer_id = cards.id"
42
42
  ).where(
43
43
  "cards.id IS NULL"
44
- ).find_in_batches do |group|
44
+ ).pluck_in_batches(:id) do |group_ids|
45
45
  # used to be .delete_all here, but that was failing on large dbs
46
46
  puts "deleting batch of references"
47
- where("id in (#{group.map(&:id).join ','})").delete_all
47
+ where("id in (#{group_ids.join ','})").delete_all
48
48
  end
49
49
  end
50
50
 
@@ -4,14 +4,11 @@ class Card
4
4
  module AdvancedApi
5
5
  def ensure_set &block
6
6
  set_module = yield
7
+ set_module = card_set_module_const_get(set_module) unless set_module.is_a?(Module)
8
+ set_module
7
9
  rescue NameError => e
8
10
  if e.message =~ /uninitialized constant (?:Card::Set::)?(.+)$/
9
- constant_pieces = Regexp.last_match(1).split("::")
10
- constant_pieces.inject(Card::Set) do |set_mod, module_name|
11
- set_mod.const_get_or_set module_name do
12
- Module.new
13
- end
14
- end
11
+ define_set Regexp.last_match(1)
15
12
  end
16
13
  # try again - there might be another submodule that doesn't exist
17
14
  ensure_set(&block)
@@ -40,6 +37,34 @@ class Card
40
37
  end
41
38
  end
42
39
  end
40
+
41
+ private
42
+
43
+ # @param set_name [String] name of the constant to be defined
44
+ def define_set set_name
45
+ constant_pieces = set_name.split("::")
46
+ constant_pieces.inject(Card::Set) do |set_mod, module_name|
47
+ set_mod.const_get_or_set module_name do
48
+ Module.new
49
+ end
50
+ end
51
+ end
52
+
53
+ # "set" is the noun not the verb
54
+ def card_set_module_const_get const
55
+ Card::Set.const_get normalize_const(const)
56
+ end
57
+
58
+ def normalize_const const
59
+ case const
60
+ when Array
61
+ const.map { |piece| piece.to_s.camelcase }.join("::")
62
+ when Symbol
63
+ const.to_s.camelcase
64
+ else
65
+ const
66
+ end
67
+ end
43
68
  end
44
69
  end
45
70
  end
@@ -1,5 +1,5 @@
1
1
  class Card
2
- def deserialize_for_active_job! attr, env, current_id
2
+ def deserialize_for_active_job! attr
3
3
  attr.each do |attname, args|
4
4
  # symbols are not allowed so all symbols arrive here as strings
5
5
  # convert strings that were symbols before back to symbols
@@ -7,15 +7,21 @@ class Card
7
7
  instance_variable_set("@#{attname}", value)
8
8
  end
9
9
  include_set_modules
10
+ end
11
+
12
+ def with_env_and_auth env, auth
10
13
  # If active jobs (and hence the integrate_with_delay events) don't run
11
14
  # in a background process then Card::Env.deserialize! decouples the
12
15
  # controller's params hash and the Card::Env's params hash with the
13
16
  # effect that params changes in the CardController get lost
14
17
  # (a crucial example are success params that are processed in
15
18
  # CardController#update_params_for_success)
16
- return if Wagn.config.active_job.queue_adapter == :inline
17
- Card::Env.deserialize! env
18
- Card::Auth.current_id = current_id
19
+ return yield if Wagn.config.active_job.queue_adapter == :inline
20
+ Card::Auth.with auth do
21
+ Card::Env.with env do
22
+ yield
23
+ end
24
+ end
19
25
  end
20
26
 
21
27
  def serialize_for_active_job
@@ -115,16 +121,18 @@ class Card
115
121
  define_method(method_name, proc do
116
122
  IntegrateWithDelayJob.set(queue: event).perform_later(
117
123
  self, serialize_for_active_job, Card::Env.serialize,
118
- Card::Auth.current_id, final_method_name
124
+ Card::Auth.serialize, final_method_name
119
125
  )
120
126
  end)
121
127
  end
122
128
  end
123
129
 
124
130
  class IntegrateWithDelayJob < ActiveJob::Base
125
- def perform card, card_attribs, env, current_id, method_name
126
- card.deserialize_for_active_job! card_attribs, env, current_id
127
- card.send method_name
131
+ def perform card, card_attribs, env, auth, method_name
132
+ card.deserialize_for_active_job! card_attribs
133
+ card.with_env_and_auth env, auth do
134
+ card.send method_name
135
+ end
128
136
  end
129
137
  end
130
138