card 1.16.12 → 1.16.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/card.gemspec +1 -1
  4. data/db/migrate_core_cards/20130823192433_add_style_cards.rb +39 -24
  5. data/db/migrate_core_cards/20140629222005_add_email_cards.rb +6 -11
  6. data/db/migrate_core_cards/20151120180631_add_token_expiration.rb +7 -0
  7. data/db/seed/new/card_actions.yml +396 -388
  8. data/db/seed/new/card_acts.yml +1 -595
  9. data/db/seed/new/card_changes.yml +8154 -23619
  10. data/db/seed/new/card_references.yml +1009 -988
  11. data/db/seed/new/cards.yml +1445 -1423
  12. data/db/seed/test/fixtures/card_actions.yml +1375 -1399
  13. data/db/seed/test/fixtures/card_acts.yml +445 -1063
  14. data/db/seed/test/fixtures/card_changes.yml +11440 -26881
  15. data/db/seed/test/fixtures/card_references.yml +1523 -1502
  16. data/db/seed/test/fixtures/cards.yml +2736 -2715
  17. data/db/seed/test/seed.rb +7 -10
  18. data/db/version_core_cards.txt +1 -1
  19. data/lib/card/auth.rb +65 -19
  20. data/lib/card/cache.rb +18 -18
  21. data/lib/card/env.rb +10 -10
  22. data/lib/card/format.rb +41 -30
  23. data/lib/card/location.rb +3 -5
  24. data/lib/card/subcards.rb +0 -3
  25. data/lib/card/success.rb +14 -11
  26. data/mod/01_core/set/all/subcards.rb +4 -2
  27. data/mod/01_core/set/all/trash.rb +4 -1
  28. data/mod/02_basic_types/set/type/pointer.rb +5 -2
  29. data/mod/05_email/set/all/notify.rb +85 -73
  30. data/mod/05_email/spec/set/all/notify_spec.rb +74 -55
  31. data/mod/05_standard/set/all/comment.rb +18 -12
  32. data/mod/05_standard/set/all/error.rb +5 -1
  33. data/mod/05_standard/set/right/account.rb +50 -73
  34. data/mod/05_standard/set/right/token.rb +49 -2
  35. data/mod/05_standard/set/self/signin.rb +14 -12
  36. data/mod/05_standard/set/type/signup.rb +17 -21
  37. data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
  38. data/mod/05_standard/spec/set/right/account_spec.rb +76 -52
  39. data/mod/05_standard/spec/set/right/password_spec.rb +10 -11
  40. data/mod/05_standard/spec/set/right/token_spec.rb +19 -1
  41. data/mod/05_standard/spec/set/type/signup_spec.rb +3 -4
  42. data/spec/lib/card/auth_spec.rb +46 -5
  43. metadata +5 -4
@@ -31,7 +31,9 @@ def clear_subcards
31
31
  end
32
32
 
33
33
  def unfilled?
34
- (content.empty? || content.strip.empty?) && !subcards.present?
34
+ (content.empty? || content.strip.empty?) &&
35
+ (comment.blank? || comment.strip.blank?) &&
36
+ !subcards.present?
35
37
  end
36
38
 
37
39
  event :reject_empty_subcards, after: :approve, on: :save do
@@ -67,4 +69,4 @@ event :store_subcards, after: :store do
67
69
  # eg. <user> creates <user+*account> creates <user+*account+*status>
68
70
  # <user> changes <user+*account+*status> in event activate_account
69
71
  Card.write_to_local_cache self
70
- end
72
+ end
@@ -28,7 +28,10 @@ event :validate_delete, before: :approve, on: :delete do
28
28
  errors.add :delete, "#{name} is is a system card. (#{codename})"
29
29
  end
30
30
 
31
- undeletable_all_rules_tags = %w{ default style layout create read update delete }
31
+ undeletable_all_rules_tags =
32
+ %w{ default style layout create read update delete }
33
+ # FIXME: HACK! should be configured in the rule
34
+
32
35
  if junction? && (l = left) && l.codename == 'all' &&
33
36
  undeletable_all_rules_tags.member?(right.codename)
34
37
  errors.add :delete, "#{name} is an indestructible rule"
@@ -1,7 +1,10 @@
1
1
 
2
+
2
3
  event :add_and_drop_items, before: :approve, on: :save do
3
- self.add_item Env.params['add_item'] if Env.params['add_item']
4
- self.drop_item Env.params['drop_item'] if Env.params['drop_item']
4
+ adds = Env.params['add_item']
5
+ drops = Env.params['drop_item']
6
+ Array.wrap(adds).each { |i| add_item i } if adds
7
+ Array.wrap(drops).each { |i| drop_item i } if drops
5
8
  end
6
9
 
7
10
  event :insert_item_event, before: :approve, on: :save, when: proc {|c| Env.params['insert_item']} do
@@ -1,37 +1,30 @@
1
1
 
2
2
  class FollowerStash
3
3
  def initialize card=nil
4
- @followed_affected_cards = Hash.new { |h,v| h[v]=[] }
4
+ @followed_affected_cards = Hash.new { |h, v| h[v] = [] }
5
5
  @visited = ::Set.new
6
6
  add_affected_card(card) if card
7
7
  end
8
8
 
9
9
  def add_affected_card card
10
+ return if @visited.include? card.key
10
11
  Auth.as_bot do
11
- if !@visited.include? card.key
12
- @visited.add card.key
13
- card.all_direct_follower_ids_with_reason do |user_id, reason|
14
- notify Card.fetch(user_id), of: reason
15
- end
16
- if card.left and !@visited.include?(card.left.name) and follow_field_rule = card.left.rule_card(:follow_fields)
17
-
18
- follow_field_rule.item_names(context: card.left.cardname).each do |item|
19
- if @visited.include? item.to_name.key
20
- add_affected_card card.left
21
- break
22
- elsif item.to_name.key == Card[:includes].key
23
- includee_set = Card.search(included_by: card.left.name).map(&:key)
24
- if !@visited.intersection(includee_set).empty?
25
- add_affected_card card.left
26
- break
27
- end
28
- end
12
+ @visited.add card.key
13
+ notify_direct_followers card
14
+ return if !(left_card = card.left) || @visited.include?(left_card.key) ||
15
+ !(follow_field_rule = left_card.rule_card(:follow_fields))
16
+ follow_field_rule.item_names(context: left_card.cardname).each do |item|
17
+ if @visited.include? item.to_name.key
18
+ add_affected_card left_card
19
+ break
20
+ elsif item.to_name.key == Card[:includes].key
21
+ includee_set = Card.search(included_by: left_card.name).map(&:key)
22
+ if !@visited.intersection(includee_set).empty?
23
+ add_affected_card left_card
24
+ break
29
25
  end
30
-
31
26
  end
32
-
33
27
  end
34
-
35
28
  end
36
29
  end
37
30
 
@@ -39,73 +32,86 @@ class FollowerStash
39
32
  @followed_affected_cards.keys
40
33
  end
41
34
 
42
- def each_follower_with_reason # "follower" is a card object, "followed" a card name
35
+ def each_follower_with_reason
36
+ # "follower"(=user) is a card object, "followed"(=reasons) a card name
43
37
  @followed_affected_cards.each do |user, reasons|
44
- yield(user,reasons.first)
38
+ yield(user, reasons.first)
45
39
  end
46
40
  end
47
41
 
48
42
  private
49
43
 
44
+ def notify_direct_followers card
45
+ card.all_direct_follower_ids_with_reason do |user_id, reason|
46
+ notify Card.fetch(user_id), of: reason
47
+ end
48
+ end
49
+
50
50
  def notify follower, because
51
51
  @followed_affected_cards[follower] << because[:of]
52
52
  end
53
-
54
53
  end
55
54
 
56
55
  def act_card
57
56
  @supercard || self
58
57
  end
59
58
 
60
-
61
59
  def followable?
62
60
  true
63
61
  end
64
62
 
63
+ def silent_change?
64
+ silent_change.nil? ? !Card::Env[:controller] : silent_change
65
+ end
66
+
65
67
  def notable_change?
66
- !silent_change && !supercard && current_act && Card::Auth.current_id != WagnBotID && followable?
68
+ !silent_change? && !supercard && current_act &&
69
+ Card::Auth.current_id != WagnBotID && followable?
67
70
  end
68
71
 
69
- event :notify_followers_after_save, after: :subsequent, on: :save, when: proc{ |ca| ca.notable_change? } do
72
+ event :notify_followers_after_save,
73
+ after: :subsequent, on: :save, when: proc { |ca| ca.notable_change? } do
70
74
  notify_followers
71
75
  end
72
76
 
73
77
  # in the delete case we have to calculate the follower_stash beforehand
74
78
  # but we can't pass the follower_stash through the ActiveJob queue.
75
- # We have to deal with the notifications in the extend phase instead of the subsequent phase
79
+ # We have to deal with the notifications in the extend phase instead of the
80
+ # subsequent phase
76
81
  event :stash_followers, after: :approve, on: :delete do
77
- act_card.follower_stash ||= FollowerStash.new
82
+ act_card.follower_stash ||= FollowerStash.new
78
83
  act_card.follower_stash.add_affected_card self
79
84
  end
80
- event :notify_followers_after_delete, after: :extend, on: :delete,
81
- when: proc{ |ca| ca.notable_change? } do
85
+ event :notify_followers_after_delete,
86
+ after: :extend, on: :delete, when: proc { |ca| ca.notable_change? } do
82
87
  notify_followers
83
88
  end
84
89
 
85
90
  def notify_followers
86
- begin
87
- @current_act.reload
88
- @follower_stash ||= FollowerStash.new
89
- @current_act.actions.each do |a|
90
- @follower_stash.add_affected_card a.card if a.card
91
- end
92
- @follower_stash.each_follower_with_reason do |follower, reason|
93
- if follower.account and follower != @current_act.actor
94
- follower.account.send_change_notice @current_act, reason[:set_card].name, reason[:option]
95
- end
91
+ @current_act.reload
92
+ @follower_stash ||= FollowerStash.new
93
+ @current_act.actions.each do |a|
94
+ @follower_stash.add_affected_card a.card if a.card
95
+ end
96
+ @follower_stash.each_follower_with_reason do |follower, reason|
97
+ if follower.account && follower != @current_act.actor
98
+ follower.account.send_change_notice @current_act, reason[:set_card].name,
99
+ reason[:option]
96
100
  end
97
- rescue =>e #this error handling should apply to all extend callback exceptions
98
- Rails.logger.info "\nController exception: #{e.message}"
99
- Card::Error.current = e
100
- notable_exception_raised
101
101
  end
102
+ # this error handling should apply to all extend callback exceptions
103
+ rescue => e
104
+ Rails.logger.info "\nController exception: #{e.message}"
105
+ Card::Error.current = e
106
+ notable_exception_raised
102
107
  end
103
108
 
104
109
  format do
105
110
  view :list_of_changes, denial: :blank do |args|
106
111
  action = get_action(args)
107
112
 
108
- relevant_fields = case action.action_type
113
+ relevant_fields =
114
+ case action.action_type
109
115
  when :create then [:cardtype, :content]
110
116
  when :update then [:name, :cardtype, :content]
111
117
  when :delete then [:content]
@@ -116,12 +122,12 @@ format do
116
122
  end.compact.join
117
123
  end
118
124
 
119
-
120
125
  view :subedits, perms: :none do |args|
121
126
  subedits =
122
127
  get_act(args).relevant_actions_for(card).map do |action|
123
128
  if action.card_id != card.id
124
- action.card.format(format: @format).render_subedit_notice(action: action)
129
+ action.card.format(format: @format)
130
+ .render_subedit_notice(action: action)
125
131
  end
126
132
  end.compact.join
127
133
 
@@ -134,16 +140,19 @@ format do
134
140
 
135
141
  view :subedit_notice, denial: :blank do |args|
136
142
  action = get_action(args)
137
- name_before_action = (action.new_values[:name] && action.old_values[:name]) || card.name
143
+ name_before_action =
144
+ (action.new_values[:name] && action.old_values[:name]) || card.name
138
145
 
139
146
  wrap_subedit_item %{#{name_before_action} #{action.action_type}d
140
147
  #{ render_list_of_changes(args) }}
141
148
  end
142
149
 
143
150
  view :followed, perms: :none, closed: true do |args|
144
- if args[:followed_set] && (set_card = Card.fetch(args[:followed_set])) &&
145
- args[:follow_option] && (option_card = Card.fetch(args[:follow_option]))
146
- option_card.description set_card
151
+ if args[:followed_set] &&
152
+ (set_card = Card.fetch(args[:followed_set])) &&
153
+ args[:follow_option] &&
154
+ (option_card = Card.fetch(args[:follow_option]))
155
+ option_card.description set_card
147
156
  else
148
157
  'followed card'
149
158
  end
@@ -154,23 +163,29 @@ format do
154
163
  end
155
164
 
156
165
  view :unfollow_url, perms: :none, closed: true do |args|
157
- if args[:followed_set] && (set_card = Card.fetch(args[:followed_set])) && args[:follow_option] && args[:follower]
158
- rule_name = set_card.follow_rule_name args[:follower]
159
- target_name = "#{args[:follower]}+#{Card[:follow].name}"
160
- update_path = page_path target_name, action: :update, card: {subcards: {rule_name=>Card[:never].name}}
161
- card_url update_path # absolutize path
166
+ if args[:followed_set] && (set_card = Card.fetch(args[:followed_set])) &&
167
+ args[:follow_option] && args[:follower]
168
+ rule_name = set_card.follow_rule_name args[:follower]
169
+ target_name = "#{args[:follower]}+#{Card[:follow].name}"
170
+ update_path = page_path target_name,
171
+ action: :update,
172
+ card: { subcards: {
173
+ rule_name => Card[:never].name
174
+ } }
175
+ card_url update_path # absolutize path
162
176
  end
163
177
  end
164
178
 
165
179
  def edit_info_for field, action
166
180
  return nil unless action.new_values[field]
167
181
 
168
- item_title = case action.action_type
169
- when :update then 'new '
170
- when :delete then 'deleted '
171
- else ''
172
- end
173
- item_title += "#{field}: "
182
+ item_title =
183
+ case action.action_type
184
+ when :update then 'new '
185
+ when :delete then 'deleted '
186
+ else ''
187
+ end
188
+ item_title += "#{field}: "
174
189
 
175
190
  item_value =
176
191
  if action.action_type == :delete
@@ -179,18 +194,20 @@ format do
179
194
  action.new_values[field]
180
195
  end
181
196
 
182
- wrap_list_item "#{item_title}#{item_value}"
197
+ wrap_list_item "#{item_title}#{item_value}"
183
198
  end
184
199
 
185
200
  def get_act args
186
- @notification_act ||= args[:act] || (args[:act_id] and Act.find(args[:act_id])) || card.acts.last
201
+ @notification_act ||= args[:act] ||
202
+ (args[:act_id] && Act.find(args[:act_id])) ||
203
+ card.acts.last
187
204
  end
188
205
 
189
206
  def get_action args
190
- args[:action] || (args[:action_id] and Action.fetch(args[:action_id])) || card.last_action
207
+ args[:action] || (args[:action_id] && Action.fetch(args[:action_id])) ||
208
+ card.last_action
191
209
  end
192
210
 
193
-
194
211
  def wrap_subedits subedits
195
212
  "\nThis update included the following changes:#{wrap_list subedits}"
196
213
  end
@@ -208,7 +225,6 @@ format do
208
225
  end
209
226
  end
210
227
 
211
-
212
228
  format :email_text do
213
229
  view :last_action, perms: :none do |args|
214
230
  act = get_act(args)
@@ -234,7 +250,3 @@ format :email_html do
234
250
  "<li>#{text}</li>\n"
235
251
  end
236
252
  end
237
-
238
-
239
-
240
-
@@ -15,7 +15,11 @@ shared_examples_for 'notifications' do
15
15
  it { is_expected.to include 'cardtype: Basic' }
16
16
  end
17
17
  context 'for a updated card' do
18
- before { @card.update_attributes!(name: 'bnn card', type: :pointer, content: 'changed content') }
18
+ before do
19
+ @card.update_attributes!(
20
+ name: 'bnn card', type: :pointer, content: 'changed content'
21
+ )
22
+ end
19
23
  it { is_expected.to include 'new content: [[changed content]]' }
20
24
  it { is_expected.to include 'new cardtype: Pointer' }
21
25
  it { is_expected.to include 'new name: bnn card' }
@@ -28,7 +32,9 @@ shared_examples_for 'notifications' do
28
32
  context 'for a given action' do
29
33
  subject do
30
34
  action = @card.last_action
31
- @card.update_attributes!(name: 'bnn card', type: :pointer, content: 'changed content')
35
+ @card.update_attributes!(
36
+ name: 'bnn card', type: :pointer, content: 'changed content'
37
+ )
32
38
  @card.format(format: format).render_list_of_changes(action: action)
33
39
  end
34
40
  it { is_expected.to include "content: #{content}" }
@@ -36,8 +42,11 @@ shared_examples_for 'notifications' do
36
42
  context 'for a given action id' do
37
43
  subject do
38
44
  action_id = @card.last_action.id
39
- @card.update_attributes!(name: 'bnn card', type: :pointer, content: 'changed content')
40
- @card.format(format: format).render_list_of_changes(action_id: action_id)
45
+ @card.update_attributes!(
46
+ name: 'bnn card', type: :pointer, content: 'changed content'
47
+ )
48
+ @card.format(format: format)
49
+ .render_list_of_changes(action_id: action_id)
41
50
  end
42
51
  it { is_expected.to include "content: #{content}" }
43
52
  end
@@ -63,7 +72,9 @@ shared_examples_for 'notifications' do
63
72
  context 'for a updated card' do
64
73
  changed_name = 'changed subedit notice'
65
74
  changed_content = 'changed content'
66
- before { @card.update_attributes!(name: changed_name, content: changed_content) }
75
+ before do
76
+ @card.update_attributes!(name: changed_name, content: changed_content)
77
+ end
67
78
  it { is_expected.to include changed_name }
68
79
  it { is_expected.to include 'updated' }
69
80
  it { is_expected.to include list_of_changes_for @card }
@@ -77,13 +88,15 @@ shared_examples_for 'notifications' do
77
88
  end
78
89
  end
79
90
 
80
-
81
91
  describe Card::Set::All::Notify do
92
+ before do
93
+ ::Card.any_instance.stub(:'silent_change?').and_return(false)
94
+ end
82
95
 
83
96
  describe 'content of notification email' do
84
97
  context 'for new card with subcards' do
85
- name = "another card with subcards"
86
- content = "main content {{+s1}} {{+s2}}"
98
+ name = 'another card with subcards'
99
+ content = 'main content {{+s1}} {{+s2}}'
87
100
  sub1_content = 'new content of subcard 1'
88
101
  sub2_content = 'new content of subcard 2'
89
102
  before do
@@ -110,9 +123,10 @@ describe Card::Set::All::Notify do
110
123
  context 'and missing permissions' do
111
124
  context 'for subcard' do
112
125
  before do
113
- Card.create_or_update! "#{name}+s1+*self+*read", type: 'Pointer', content: '[[Administrator]]'
126
+ Card.create_or_update! "#{name}+s1+*self+*read",
127
+ type: 'Pointer', content: '[[Administrator]]'
114
128
  end
115
- it "excludes subcard content" do
129
+ it 'excludes subcard content' do
116
130
  is_expected.not_to include sub1_content
117
131
  is_expected.to include sub2_content
118
132
  end
@@ -123,40 +137,45 @@ describe Card::Set::All::Notify do
123
137
  context: @card.refresh(true),
124
138
  to: Card['Joe User'].email,
125
139
  follower: Card['Joe User'].name,
126
- followed_set: @card.name+"+s1+*self",
140
+ followed_set: @card.name+'+s1+*self',
127
141
  follow_option: '*always'
128
142
  ).text_part.body.raw_source
129
143
  }
130
144
  before do
131
- Card.create_or_update! "#{name}+*self+*read",type: 'Pointer',content: '[[Administrator]]'
132
- Card.create_or_update! "#{name}+s1+*self+*read",type: 'Pointer',content: '[[Anyone]]'
145
+ Card.create_or_update! "#{name}+*self+*read",
146
+ type: 'Pointer', content: '[[Administrator]]'
147
+ Card.create_or_update! "#{name}+s1+*self+*read",
148
+ type: 'Pointer',content: '[[Anyone]]'
133
149
  end
134
150
  it 'includes subcard content' do
135
151
  is_expected.to include sub1_content
136
152
  end
137
- it "excludes maincard content" do
153
+ it 'excludes maincard content' do
138
154
  is_expected.not_to include content
139
155
  is_expected.not_to be_empty
140
156
  end
141
157
  end
142
158
  context 'for all parts' do
143
159
  before do
144
- Card.create_or_update! "#{name}+s1+*self+*read",type: 'Pointer',content: '[[Administrator]]'
145
- Card.create_or_update! "#{name}+s2+*self+*read",type: 'Pointer',content: '[[Administrator]]'
146
- Card.create_or_update! "#{name}+*self+*read",type: 'Pointer',content: '[[Administrator]]'
160
+ Card.create_or_update! "#{name}+s1+*self+*read",
161
+ type: 'Pointer', content: '[[Administrator]]'
162
+ Card.create_or_update! "#{name}+s2+*self+*read",
163
+ type: 'Pointer', content: '[[Administrator]]'
164
+ Card.create_or_update! "#{name}+*self+*read",
165
+ type: 'Pointer', content: '[[Administrator]]'
147
166
  end
148
167
  it { is_expected.not_to include content }
149
168
  it { is_expected.not_to include sub1_content }
150
169
  it { is_expected.not_to include sub2_content }
151
- it "will not be send" do
152
- expect(Card['Joe User'].account.changes_visible? @card.acts.last).to be_falsey
170
+ it 'will not be send' do
171
+ expect(Card['Joe User'].account.changes_visible? @card.acts.last)
172
+ .to be_falsey
153
173
  end
154
174
  end
155
175
  end
156
176
  end
157
177
  end
158
178
 
159
-
160
179
  describe 'html format' do
161
180
  include_examples 'notifications' do
162
181
  let(:format) { 'email_html' }
@@ -169,8 +188,8 @@ describe Card::Set::All::Notify do
169
188
  end
170
189
 
171
190
  it 'creates well formatted text message' do
172
- name = "another card with subcards"
173
- content = "main content {{+s1}} {{+s2}}"
191
+ name = 'another card with subcards'
192
+ content = 'main content {{+s1}} {{+s2}}'
174
193
  sub1_content = 'new content of subcard 1'
175
194
  sub2_content = 'new content of subcard 2'
176
195
  Card::Auth.as_bot do
@@ -235,56 +254,56 @@ Use this link to unfollow /update/Joe_User+*follow?card%5Bsubcards%5D%5Banother+
235
254
 
236
255
 
237
256
 
238
- it "sends notifications of edits" do
239
- expect_user("Big Brother").to be_notified_of "All Eyes On Me+*self"
240
- update "All Eyes On Me"
257
+ it 'sends notifications of edits' do
258
+ expect_user('Big Brother').to be_notified_of 'All Eyes On Me+*self'
259
+ update 'All Eyes On Me'
241
260
  end
242
261
 
243
- it "does not send notification to author of change" do
262
+ it 'does not send notification to author of change' do
244
263
  Card::Auth.current_id = Card['Big Brother'].id
245
- expect_user("Big Brother").not_to be_notified
246
- update "Google glass"
264
+ expect_user('Big Brother').not_to be_notified
265
+ update 'Google glass'
247
266
  end
248
267
 
249
- it "sends only one notification per user" do
250
- expect_user("Big Brother").to receive(:send_change_notice).exactly(1)
251
- update "Google glass"
268
+ it 'sends only one notification per user' do
269
+ expect_user('Big Brother').to receive(:send_change_notice).exactly(1)
270
+ update 'Google glass'
252
271
  end
253
272
 
254
- it "does not send notification of not-followed cards" do
255
- expect_user("Big Brother").not_to be_notified
256
- update "No One Sees Me"
273
+ it 'does not send notification of not-followed cards' do
274
+ expect_user('Big Brother').not_to be_notified
275
+ update 'No One Sees Me'
257
276
  end
258
277
 
259
278
 
260
279
 
261
- context "when following *type sets" do
280
+ context 'when following *type sets' do
262
281
  before do
263
282
  Card::Auth.current_id = Card['joe admin'].id
264
283
  end
265
284
 
266
- it "sends notifications of new card" do
267
- new_card = Card.new name: "Microscope", type: "Optic"
268
- expect_user("Optic fan").to be_notified_of "Optic+*type", "*always"
285
+ it 'sends notifications of new card' do
286
+ new_card = Card.new name: 'Microscope', type: 'Optic'
287
+ expect_user('Optic fan').to be_notified_of 'Optic+*type', '*always'
269
288
  new_card.save!
270
289
  end
271
290
 
272
- it "sends notification of update" do
273
- expect_user("Optic fan").to be_notified_of "Optic+*type", '*always'
274
- update "Sunglasses"
291
+ it 'sends notification of update' do
292
+ expect_user('Optic fan').to be_notified_of 'Optic+*type', '*always'
293
+ update 'Sunglasses'
275
294
  end
276
295
  end
277
296
 
278
297
  context 'when following *right sets' do
279
- it "sends notifications of new card" do
280
- new_card = Card.new name: "Telescope+lens"
281
- expect_user("Big Brother").to be_notified_of "lens+*right", '*always'
298
+ it 'sends notifications of new card' do
299
+ new_card = Card.new name: 'Telescope+lens'
300
+ expect_user('Big Brother').to be_notified_of 'lens+*right', '*always'
282
301
  new_card.save!
283
302
  end
284
303
 
285
- it "sends notifications of update" do
286
- expect_user("Big Brother").to be_notified_of "lens+*right", '*always'
287
- update "Magnifier+lens"
304
+ it 'sends notifications of update' do
305
+ expect_user('Big Brother').to be_notified_of 'lens+*right', '*always'
306
+ update 'Magnifier+lens'
288
307
  end
289
308
  end
290
309
 
@@ -302,8 +321,8 @@ Use this link to unfollow /update/Joe_User+*follow?card%5Bsubcards%5D%5Banother+
302
321
  end
303
322
  end
304
323
 
305
- describe "notifications of fields" do
306
- context "when following ascendant" do
324
+ describe 'notifications of fields' do
325
+ context 'when following ascendant' do
307
326
  it "doesn't sends notification of arbitrary subcards" do
308
327
  expect_user('Sunglasses fan').not_to be_notified
309
328
  Card.create name: 'Sunglasses+about'
@@ -322,21 +341,21 @@ Use this link to unfollow /update/Joe_User+*follow?card%5Bsubcards%5D%5Banother+
322
341
  end
323
342
  end
324
343
 
325
- context "and follow fields rule contains *include" do
326
- it "sends notification of new included card" do
344
+ context 'and follow fields rule contains *include' do
345
+ it 'sends notification of new included card' do
327
346
  new_card = Card.new name: 'Sunglasses+lens'
328
- expect_user("Sunglasses fan").to be_notified_of "Sunglasses+*self"
347
+ expect_user('Sunglasses fan').to be_notified_of 'Sunglasses+*self'
329
348
  new_card.save!
330
349
  end
331
350
 
332
- it "sends notification of updated included card" do
333
- expect_user("Sunglasses fan").to be_notified_of "Sunglasses+*self"
351
+ it 'sends notification of updated included card' do
352
+ expect_user('Sunglasses fan').to be_notified_of 'Sunglasses+*self'
334
353
  update 'Sunglasses+tint'
335
354
  end
336
355
 
337
356
  it "doesn't send notification of not included card" do
338
357
  new_card = Card.new name: 'Sunglasses+frame'
339
- expect_user("Sunglasses fan").not_to be_notified
358
+ expect_user('Sunglasses fan').not_to be_notified
340
359
  new_card.save!
341
360
  end
342
361
  end