card 1.16.14 → 1.16.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
- data/lib/card/auth.rb +15 -10
- data/lib/card/codename.rb +25 -21
- data/lib/card/content.rb +100 -68
- data/lib/card/format.rb +158 -129
- data/lib/card/query.rb +15 -9
- data/lib/card/query/attributes.rb +41 -49
- data/lib/card/set.rb +15 -12
- data/lib/card/set_pattern.rb +4 -5
- data/lib/card/spec_helper.rb +54 -16
- data/lib/cardio.rb +43 -25
- data/mod/01_core/chunk/include.rb +1 -1
- data/mod/01_core/set/all/collection.rb +76 -73
- data/mod/01_core/set/all/content.rb +0 -4
- data/mod/01_core/set/all/fetch.rb +35 -42
- data/mod/01_core/set/all/name.rb +17 -7
- data/mod/01_core/set/all/pattern.rb +12 -11
- data/mod/01_core/set/all/permissions.rb +51 -42
- data/mod/01_core/set/all/phases.rb +2 -1
- data/mod/01_core/set/all/references.rb +2 -2
- data/mod/01_core/set/all/rules.rb +28 -35
- data/mod/01_core/set/all/subcards.rb +12 -12
- data/mod/01_core/set/all/tracked_attributes.rb +1 -1
- data/mod/01_core/set/all/type.rb +11 -11
- data/mod/01_core/set/all/utils.rb +6 -1
- data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
- data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
- data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
- data/mod/01_history/lib/card/action.rb +52 -47
- data/mod/01_history/set/all/actions.rb +20 -16
- data/mod/01_history/set/all/history.rb +18 -13
- data/mod/02_basic_types/set/all/base.rb +23 -2
- data/mod/02_basic_types/set/type/pointer.rb +45 -36
- data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
- data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
- data/mod/03_machines/set/right/machine_output.rb +10 -6
- data/mod/04_settings/set/abstract/permission.rb +10 -5
- data/mod/04_settings/set/type/setting.rb +4 -1
- data/mod/05_email/set/all/follow.rb +39 -44
- data/mod/05_email/set/all/notify.rb +4 -1
- data/mod/05_email/set/right/followers.rb +16 -14
- data/mod/05_email/set/self/follow_defaults.rb +22 -19
- data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
- data/mod/05_standard/set/abstract/attachment.rb +85 -58
- data/mod/05_standard/set/all/comment.rb +35 -19
- data/mod/05_standard/set/all/error.rb +124 -98
- data/mod/05_standard/set/all/list_changes.rb +27 -22
- data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
- data/mod/05_standard/set/all/rich_html/form.rb +123 -81
- data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
- data/mod/05_standard/set/right/account.rb +2 -2
- data/mod/05_standard/set/right/email.rb +3 -2
- data/mod/05_standard/set/rstar/rules.rb +3 -3
- data/mod/05_standard/set/self/search.rb +45 -22
- data/mod/05_standard/set/type/cardtype.rb +13 -11
- data/mod/05_standard/set/type/listed_by.rb +3 -2
- data/mod/05_standard/set/type/set.rb +17 -13
- data/mod/05_standard/set/type/signup.rb +1 -2
- data/mod/05_standard/set/type/user.rb +1 -1
- data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
- data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
- data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
- data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
- data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
- data/spec/models/card/trash_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- metadata +2 -2
@@ -6,9 +6,30 @@ format do
|
|
6
6
|
end
|
7
7
|
|
8
8
|
# NAME VIEWS
|
9
|
-
|
10
9
|
simple_args = { closed: true, perms: :none }
|
11
|
-
view
|
10
|
+
view :name, simple_args do |args|
|
11
|
+
return card.name unless args[:variant]
|
12
|
+
args[:variant].split(/[\s,]+/).inject(card.name) do |name, variant|
|
13
|
+
case variant.to_sym
|
14
|
+
when :capitalized
|
15
|
+
name.capitalize
|
16
|
+
when :singular
|
17
|
+
name.singularize
|
18
|
+
when :plural
|
19
|
+
name.pluralize
|
20
|
+
when :title
|
21
|
+
name.titleize
|
22
|
+
else
|
23
|
+
if ::Set.new([
|
24
|
+
:downcase, :upcase, :swapcase, :reverse, :succ
|
25
|
+
]).include?(variant.to_sym)
|
26
|
+
name.send variant
|
27
|
+
else
|
28
|
+
name
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
12
33
|
view(:key, simple_args) { card.key }
|
13
34
|
view(:title, simple_args) { |args| args[:title] || card.name }
|
14
35
|
view(:linkname, simple_args) { card.cardname.url_key }
|
@@ -12,6 +12,20 @@ event :insert_item_event, before: :approve, on: :save, when: proc {|c| Env.param
|
|
12
12
|
self.insert_item index.to_i, Env.params['insert_item']
|
13
13
|
end
|
14
14
|
|
15
|
+
phase_method :changed_item_names do
|
16
|
+
dropped_item_names + added_item_names
|
17
|
+
end
|
18
|
+
|
19
|
+
phase_method :dropped_item_names do
|
20
|
+
old_items = item_names content: db_content_was
|
21
|
+
old_items - item_names
|
22
|
+
end
|
23
|
+
|
24
|
+
phase_method :added_item_names do
|
25
|
+
old_items = item_names content: db_content_was
|
26
|
+
item_names - old_items
|
27
|
+
end
|
28
|
+
|
15
29
|
format do
|
16
30
|
def item_links args={}
|
17
31
|
card.item_cards(args).map do |item_card|
|
@@ -290,37 +304,38 @@ def item_type
|
|
290
304
|
end
|
291
305
|
|
292
306
|
def items= array
|
293
|
-
self.content=''
|
307
|
+
self.content = ''
|
294
308
|
array.each { |i| self << i }
|
295
309
|
save!
|
296
310
|
end
|
297
311
|
|
298
312
|
def << item
|
299
|
-
newname =
|
300
|
-
|
301
|
-
when
|
302
|
-
|
313
|
+
newname =
|
314
|
+
case item
|
315
|
+
when Card then item.name
|
316
|
+
when Integer then (c = Card[item]) && c.name
|
317
|
+
else item
|
303
318
|
end
|
304
319
|
add_item newname
|
305
320
|
end
|
306
321
|
|
307
322
|
def add_item name
|
308
|
-
|
309
|
-
|
310
|
-
end
|
323
|
+
return if include_item? name
|
324
|
+
self.content = "[[#{(item_names << name).reject(&:blank?) * "]]\n[["}]]"
|
311
325
|
end
|
326
|
+
|
312
327
|
def add_item! name
|
313
328
|
add_item name
|
314
329
|
save!
|
315
330
|
end
|
316
331
|
|
317
332
|
def drop_item name
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
end
|
333
|
+
return unless include_item? name
|
334
|
+
key = name.to_name.key
|
335
|
+
new_names = item_names.reject { |n| n.to_name.key == key }
|
336
|
+
self.content = new_names.empty? ? '' : "[[#{new_names * "]]\n[["}]]"
|
323
337
|
end
|
338
|
+
|
324
339
|
def drop_item! name
|
325
340
|
drop_item name
|
326
341
|
save!
|
@@ -328,43 +343,37 @@ end
|
|
328
343
|
|
329
344
|
def insert_item index, name
|
330
345
|
new_names = item_names
|
331
|
-
new_names.delete
|
332
|
-
new_names.insert
|
333
|
-
self.content =
|
346
|
+
new_names.delete name
|
347
|
+
new_names.insert index, name
|
348
|
+
self.content = new_names.map { |new_name| "[[#{new_name}]]" }.join "\n"
|
334
349
|
end
|
350
|
+
|
335
351
|
def insert_item! index, name
|
336
352
|
insert_item index, name
|
337
353
|
save!
|
338
354
|
end
|
339
355
|
|
340
|
-
|
341
356
|
def options_rule_card
|
342
|
-
|
357
|
+
rule_card :options
|
343
358
|
end
|
344
359
|
|
345
360
|
def option_names
|
346
|
-
|
347
|
-
oc
|
348
|
-
|
349
|
-
|
350
|
-
|
361
|
+
result_names =
|
362
|
+
if (oc = options_rule_card)
|
363
|
+
oc.item_names default_limit: 50, context: name
|
364
|
+
else
|
365
|
+
Card.search({ sort: 'name', limit: 50, return: :name },
|
366
|
+
"option names for pointer: #{name}")
|
367
|
+
end
|
351
368
|
if (selected_options = item_names)
|
352
|
-
|
369
|
+
result_names += selected_options
|
370
|
+
result_names.uniq!
|
353
371
|
end
|
354
|
-
|
372
|
+
result_names
|
355
373
|
end
|
356
374
|
|
357
375
|
def option_cards
|
358
|
-
|
359
|
-
|
360
|
-
else
|
361
|
-
Card.search sort: 'alpha', limit: 50
|
362
|
-
end
|
363
|
-
if (selected_options = item_names)
|
364
|
-
selected_options.each do |item|
|
365
|
-
result_cards.push Card.fetch(item,new: {})
|
366
|
-
end
|
367
|
-
result_cards.uniq!
|
376
|
+
option_names.map do |name|
|
377
|
+
Card.fetch name, new: {}
|
368
378
|
end
|
369
|
-
result_cards
|
370
379
|
end
|
@@ -1,26 +1,41 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
3
|
describe Card::Set::All::Base do
|
4
|
-
|
5
4
|
describe 'handles view' do
|
5
|
+
describe 'name view' do
|
6
|
+
it('name') { expect(render_card(:name)).to eq('Tempo Rary') }
|
7
|
+
it 'pluralizes' do
|
8
|
+
name = render_content '{{Joe User|name; variant: plural}}'
|
9
|
+
expect(name).to eq('Joe Users')
|
10
|
+
end
|
11
|
+
it 'singularizes' do
|
12
|
+
name = render_content '{{Sunglasses|name; variant: singular}}'
|
13
|
+
expect(name).to eq('Sunglass')
|
14
|
+
end
|
15
|
+
it 'handles more than one variant' do
|
16
|
+
name = render_content(
|
17
|
+
'{{Sunglasses|name; variant: singular, upcase}}'
|
18
|
+
)
|
19
|
+
expect(name).to eq('SUNGLASS')
|
20
|
+
end
|
21
|
+
end
|
6
22
|
|
7
|
-
it(
|
8
|
-
it(
|
9
|
-
it("linkname") { expect(render_card(:linkname)).to eq('Tempo_Rary') }
|
23
|
+
it('key' ) { expect(render_card(:key)).to eq('tempo_rary') }
|
24
|
+
it('linkname') { expect(render_card(:linkname)).to eq('Tempo_Rary') }
|
10
25
|
|
11
|
-
it
|
26
|
+
it 'url' do
|
12
27
|
Card::Env[:protocol] = 'http://'
|
13
28
|
Card::Env[:host] = 'eric.skippy.com'
|
14
29
|
expect(render_card(:url)).to eq('http://eric.skippy.com/Tempo_Rary')
|
15
30
|
end
|
16
31
|
|
17
32
|
it :raw do
|
18
|
-
@a = Card.new content:
|
19
|
-
expect(@a.format._render(:raw)).to eq(
|
33
|
+
@a = Card.new content: '{{A}}'
|
34
|
+
expect(@a.format._render(:raw)).to eq('{{A}}')
|
20
35
|
end
|
21
36
|
|
22
|
-
it
|
23
|
-
expect(render_card(:core, name: 'A+B')).to eq(
|
37
|
+
it 'core' do
|
38
|
+
expect(render_card(:core, name: 'A+B')).to eq('AlphaBeta')
|
24
39
|
end
|
25
40
|
|
26
41
|
it 'core for new card' do
|
@@ -28,26 +43,28 @@ describe Card::Set::All::Base do
|
|
28
43
|
end
|
29
44
|
|
30
45
|
describe 'array' do
|
31
|
-
it
|
32
|
-
Card.create! name:
|
46
|
+
it 'of search items' do
|
47
|
+
Card.create! name: 'n+a', type: 'Number', content: '10'
|
33
48
|
sleep 1
|
34
|
-
Card.create! name:
|
49
|
+
Card.create! name: 'n+b', type: 'Phrase', content: "say:\"what\""
|
35
50
|
sleep 1
|
36
|
-
Card.create! name:
|
37
|
-
c = Card.new name: 'nplusarray',
|
38
|
-
|
51
|
+
Card.create! name: 'n+c', type: 'Number', content: '30'
|
52
|
+
c = Card.new name: 'nplusarray',
|
53
|
+
content: '{{n+*children+by create|array}}'
|
54
|
+
expect(c.format._render(:core)).to eq(%{["10", "say:\\"what\\"", "30"]})
|
39
55
|
end
|
40
56
|
|
41
|
-
it
|
42
|
-
Card.create! name:
|
43
|
-
Card.create! name:
|
44
|
-
Card.create! name:
|
45
|
-
Card.create! name:
|
46
|
-
|
47
|
-
|
57
|
+
it 'of pointer items' do
|
58
|
+
Card.create! name: 'n+a', type: 'Number', content: '10'
|
59
|
+
Card.create! name: 'n+b', type: 'Number', content: '20'
|
60
|
+
Card.create! name: 'n+c', type: 'Number', content: '30'
|
61
|
+
Card.create! name: 'npoint', type: 'Pointer',
|
62
|
+
content: "[[n+a]]\n[[n+b]]\n[[n+c]]"
|
63
|
+
c = Card.new name: 'npointArray', content: '{{npoint|array}}'
|
64
|
+
expect(c.format._render(:core)).to eq(%{["10", "20", "30"]})
|
48
65
|
end
|
49
66
|
|
50
|
-
it
|
67
|
+
it 'of basic items' do
|
51
68
|
expect(render_card(:array, content: 'yoing')).to eq(%{["yoing"]})
|
52
69
|
end
|
53
70
|
end
|
@@ -69,4 +86,3 @@ describe Card::Set::All::Base do
|
|
69
86
|
end
|
70
87
|
end
|
71
88
|
end
|
72
|
-
|
@@ -50,6 +50,93 @@ describe Card::Set::Type::Pointer do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
|
53
|
+
let(:pointer) do
|
54
|
+
Card.create name: 'tp', type: 'pointer',
|
55
|
+
content: "[[item1]]\n[[item2]]"
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#added_item_names' do
|
59
|
+
it 'recognizes added items' do
|
60
|
+
Card::Auth.as_bot do
|
61
|
+
pointer
|
62
|
+
in_phase before: :approve,
|
63
|
+
on: :save,
|
64
|
+
trigger: ->{
|
65
|
+
pointer.update_attributes!(
|
66
|
+
content: "[[item1]]\n[[item2]]\n[[item3]]"
|
67
|
+
)
|
68
|
+
} do
|
69
|
+
expect(added_item_names).to eq ['item3']
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'ignores order' do
|
75
|
+
Card::Auth.as_bot do
|
76
|
+
pointer
|
77
|
+
in_phase before: :approve,
|
78
|
+
on: :save,
|
79
|
+
trigger: ->{
|
80
|
+
pointer.update_attributes!(
|
81
|
+
content: "[[item2]]\n[[item1]]"
|
82
|
+
)
|
83
|
+
} do
|
84
|
+
expect(added_item_names).to eq []
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#dropped_item_names' do
|
91
|
+
it 'recognizes dropped items' do
|
92
|
+
Card::Auth.as_bot do
|
93
|
+
pointer
|
94
|
+
in_phase before: :approve,
|
95
|
+
on: :save,
|
96
|
+
trigger: ->{
|
97
|
+
pointer.update_attributes!(
|
98
|
+
content: "[[item1]]"
|
99
|
+
)
|
100
|
+
} do
|
101
|
+
expect(dropped_item_names).to eq ['item2']
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'ignores order' do
|
107
|
+
Card::Auth.as_bot do
|
108
|
+
pointer
|
109
|
+
in_phase before: :approve,
|
110
|
+
on: :save,
|
111
|
+
trigger: ->{
|
112
|
+
pointer.update_attributes!(
|
113
|
+
content: "[[item2]]\n[[item1]]"
|
114
|
+
)
|
115
|
+
} do
|
116
|
+
expect(dropped_item_names).to eq []
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#changed_item_names' do
|
123
|
+
it 'recognizes changed items' do
|
124
|
+
Card::Auth.as_bot do
|
125
|
+
pointer
|
126
|
+
in_phase before: :approve,
|
127
|
+
on: :save,
|
128
|
+
trigger: ->{
|
129
|
+
pointer.update_attributes!(
|
130
|
+
content: "[[item1]]\n[[item3]]"
|
131
|
+
)
|
132
|
+
} do
|
133
|
+
expect(changed_item_names.sort).to eq ['item2','item3']
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
|
53
140
|
|
54
141
|
describe 'html' do
|
55
142
|
before do
|
@@ -9,7 +9,7 @@ end
|
|
9
9
|
format do
|
10
10
|
view :not_found do |args|
|
11
11
|
if update_machine_output_live?
|
12
|
-
Card::Cache.reset_global # FIXME
|
12
|
+
Card::Cache.reset_global # FIXME: wow, this is overkill, no?
|
13
13
|
root.error_status = 302
|
14
14
|
card.left.update_machine_output
|
15
15
|
card_path card.left.machine_output_url
|
@@ -19,10 +19,14 @@ format do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def update_machine_output_live?
|
22
|
-
|
23
|
-
card.left.
|
24
|
-
|
25
|
-
|
22
|
+
case
|
23
|
+
when !card.left.is_a?(Machine) then false # must be a machine
|
24
|
+
when card.left.locked? then false # machine must not be running
|
25
|
+
when card.new_card? then true # always update if new
|
26
|
+
else
|
27
|
+
# must want current output (won't re-output old stuff)
|
28
|
+
(selected_id = card.selected_action_id) &&
|
29
|
+
selected_id == card.last_action_id
|
30
|
+
end
|
26
31
|
end
|
27
|
-
|
28
32
|
end
|
@@ -3,13 +3,16 @@ def standardize_items
|
|
3
3
|
end
|
4
4
|
|
5
5
|
format :html do
|
6
|
-
|
7
|
-
|
8
|
-
%{<div class="pointer-list">#{ render_pointer_items args }</div>}
|
6
|
+
view :pointer_core do |args| # view: :core, mod: Type::Pointer::HtmlFormat
|
7
|
+
%{<div class="pointer-list">#{render_pointer_items args}</div>}
|
9
8
|
end
|
10
9
|
|
11
10
|
view :core do |args|
|
12
|
-
card.content=='_left'
|
11
|
+
if card.content == '_left'
|
12
|
+
core_inherit_content args
|
13
|
+
else
|
14
|
+
render :pointer_core, args
|
15
|
+
end
|
13
16
|
end
|
14
17
|
|
15
18
|
view :closed_content do |args|
|
@@ -22,7 +25,9 @@ format :html do
|
|
22
25
|
set_card = Card.fetch(set_name)
|
23
26
|
not_set = set_card && set_card.type_id != SetID
|
24
27
|
|
25
|
-
group_options = Auth.as_bot
|
28
|
+
group_options = Auth.as_bot do
|
29
|
+
Card.search({ type_id: RoleID, sort: 'name' }, 'roles by name')
|
30
|
+
end
|
26
31
|
|
27
32
|
inheritable = not_set ? false : set_card.inheritable?
|
28
33
|
inheriting = inheritable && card.content=='_left'
|
@@ -2,7 +2,10 @@ require_dependency 'json'
|
|
2
2
|
|
3
3
|
def self.member_names
|
4
4
|
@@member_names ||= begin
|
5
|
-
Card.search(
|
5
|
+
Card.search(
|
6
|
+
{ type_id: SettingID, return: 'key' },
|
7
|
+
'all setting cards'
|
8
|
+
).inject({}) do |hash, card_key|
|
6
9
|
hash[card_key] = true
|
7
10
|
hash
|
8
11
|
end
|
@@ -2,30 +2,33 @@ card_accessor :followers
|
|
2
2
|
|
3
3
|
FOLLOWER_IDS_CACHE_KEY = 'FOLLOWER_IDS'
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
# FIXME: this should be in type/set
|
6
|
+
event :cache_expired_for_new_set,
|
7
|
+
before: :store, on: :create,
|
8
|
+
when: proc { |c| c.type_id == Card::SetID } do
|
7
9
|
Card.follow_caches_expired
|
8
10
|
end
|
9
11
|
|
10
|
-
event :cache_expired_for_type_change, before: :store,
|
11
|
-
|
12
|
+
event :cache_expired_for_type_change, before: :store, on: :update,
|
13
|
+
changed: :type_id do
|
14
|
+
# FIXME: expire (also?) after save
|
12
15
|
Card.follow_caches_expired
|
13
16
|
end
|
14
17
|
|
15
|
-
event :cache_expired_for_name_change, before: :store,
|
18
|
+
event :cache_expired_for_name_change, before: :store, on: :update,
|
19
|
+
changed: :name do
|
16
20
|
Card.follow_caches_expired
|
17
21
|
end
|
18
22
|
|
19
|
-
event :cache_expired_for_new_user_rule,
|
20
|
-
|
21
|
-
|
23
|
+
event :cache_expired_for_new_user_rule,
|
24
|
+
before: :extend,
|
25
|
+
when: proc { |c| c.follow_rule_card? } do
|
22
26
|
Card.follow_caches_expired
|
23
27
|
end
|
24
28
|
|
25
29
|
format do
|
26
|
-
|
27
30
|
def follow_link_hash args
|
28
|
-
toggle = args[:toggle] || (
|
31
|
+
toggle = args[:toggle] || (card.followed? ? :off : :on)
|
29
32
|
hash = { class: "follow-toggle-#{toggle}" }
|
30
33
|
these_emails = "emails about changes to #{card.follow_label}"
|
31
34
|
case toggle
|
@@ -40,14 +43,13 @@ format do
|
|
40
43
|
end
|
41
44
|
set_card = card.default_follow_set_card
|
42
45
|
hash[:path] = path(
|
43
|
-
name: set_card.follow_rule_name(
|
46
|
+
name: set_card.follow_rule_name(Auth.current.name),
|
44
47
|
action: :update,
|
45
48
|
success: { layout: :modal, view: :follow_status },
|
46
49
|
card: { content: "[[#{hash[:content]}]]" }
|
47
50
|
)
|
48
51
|
hash
|
49
52
|
end
|
50
|
-
|
51
53
|
end
|
52
54
|
|
53
55
|
format :json do
|
@@ -57,13 +59,16 @@ format :json do
|
|
57
59
|
end
|
58
60
|
|
59
61
|
format :html do
|
60
|
-
|
61
62
|
view :follow_link, tags: :unknown_ok, perms: :none do |args|
|
62
63
|
hash = follow_link_hash args
|
63
64
|
text = args[:icon] ? glyphicon('flag') : ''
|
64
|
-
|
65
|
-
|
66
|
-
|
65
|
+
span_attrs = 'follow-verb menu-item-label'
|
66
|
+
text += %[<span class="#{span_attrs}">#{hash[:verb]}</span>].html_safe
|
67
|
+
# follow_rule_card = Card.fetch(
|
68
|
+
# card.default_follow_set_card.follow_rule_name(Auth.current.name),
|
69
|
+
# new: {}
|
70
|
+
# )
|
71
|
+
opts = (args[:html_args] || {}).clone
|
67
72
|
opts.merge!(
|
68
73
|
title: hash[:title],
|
69
74
|
'data-path' => hash[:path],
|
@@ -73,10 +78,8 @@ format :html do
|
|
73
78
|
opts[:class] = "follow-link #{opts[:class]}"
|
74
79
|
link_to text, hash[:path], opts
|
75
80
|
end
|
76
|
-
|
77
81
|
end
|
78
82
|
|
79
|
-
|
80
83
|
def follow_label
|
81
84
|
name
|
82
85
|
end
|
@@ -91,7 +94,6 @@ def follower_names
|
|
91
94
|
followers.map(&:name)
|
92
95
|
end
|
93
96
|
|
94
|
-
|
95
97
|
def follow_rule_card?
|
96
98
|
is_user_rule? && rule_setting_name == '*follow'
|
97
99
|
end
|
@@ -100,19 +102,16 @@ def follow_option?
|
|
100
102
|
codename && FollowOption.codenames.include?(codename.to_sym)
|
101
103
|
end
|
102
104
|
|
103
|
-
# used for the follow menu
|
104
|
-
#
|
105
|
-
#
|
106
|
-
# instead it checks whether he is following the complete set
|
105
|
+
# used for the follow menu overwritten in type/set.rb and type/cardtype.rb
|
106
|
+
# for sets and cardtypes it doesn't check whether the users is following the
|
107
|
+
# card itself instead it checks whether he is following the complete set
|
107
108
|
def followed_by? user_id
|
108
109
|
with_follower_candidate_ids do
|
109
|
-
if follow_rule_applies? user_id
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
return false
|
110
|
+
return true if follow_rule_applies? user_id
|
111
|
+
return true if (left_card = left) &&
|
112
|
+
left_card.followed_field?(self) &&
|
113
|
+
left_card.followed_by?(user_id)
|
114
|
+
false
|
116
115
|
end
|
117
116
|
end
|
118
117
|
|
@@ -120,16 +119,14 @@ def followed?
|
|
120
119
|
followed_by? Auth.current_id
|
121
120
|
end
|
122
121
|
|
123
|
-
|
124
122
|
def follow_rule_applies? follower_id
|
125
123
|
follow_rule = rule :follow, user_id: follower_id
|
126
124
|
if follow_rule.present?
|
127
125
|
follow_rule.split("\n").each do |value|
|
128
|
-
|
129
126
|
value_code = value.to_name.code
|
130
127
|
accounted_ids = (
|
131
|
-
@follower_candidate_ids[
|
132
|
-
if block = FollowOption.follower_candidate_ids[
|
128
|
+
@follower_candidate_ids[value_code] ||=
|
129
|
+
if (block = FollowOption.follower_candidate_ids[value_code])
|
133
130
|
block.call self
|
134
131
|
else
|
135
132
|
[]
|
@@ -137,37 +134,35 @@ def follow_rule_applies? follower_id
|
|
137
134
|
)
|
138
135
|
|
139
136
|
applicable =
|
140
|
-
if test = FollowOption.test[
|
137
|
+
if (test = FollowOption.test[value_code])
|
141
138
|
test.call follower_id, accounted_ids
|
142
139
|
else
|
143
140
|
accounted_ids.include? follower_id
|
144
141
|
end
|
145
142
|
|
146
|
-
return value.gsub(
|
143
|
+
return value.gsub(/[\[\]]/, '') if applicable
|
147
144
|
end
|
148
145
|
end
|
149
|
-
|
146
|
+
false
|
150
147
|
end
|
151
148
|
|
152
|
-
|
153
149
|
def with_follower_candidate_ids
|
154
150
|
@follower_candidate_ids = {}
|
155
151
|
yield
|
156
152
|
@follower_candidate_ids = nil
|
157
153
|
end
|
158
154
|
|
159
|
-
|
160
155
|
# the set card to be followed if you want to follow changes of card
|
161
156
|
def default_follow_set_card
|
162
157
|
Card.fetch("#{name}+*self")
|
163
158
|
end
|
164
159
|
|
165
|
-
|
166
160
|
# returns true if according to the follow_field_rule followers of self also
|
167
161
|
# follow changes of field_card
|
168
162
|
def followed_field? field_card
|
169
|
-
(follow_field_rule = rule_card(:follow_fields)) ||
|
170
|
-
|
163
|
+
(follow_field_rule = rule_card(:follow_fields)) ||
|
164
|
+
follow_field_rule.item_names.find do |item|
|
165
|
+
item.to_name.key == field_card.key || (item.to_name.key == Card[:includes].key && included_card_ids.include?(field_card.id) )
|
171
166
|
end
|
172
167
|
end
|
173
168
|
|
@@ -195,7 +190,7 @@ end
|
|
195
190
|
# all ids of users that follow this card because of a follow rule that applies
|
196
191
|
# to this card doesn't include users that follow this card because they are
|
197
192
|
# following parent cards or other cards that include this card
|
198
|
-
def direct_follower_ids
|
193
|
+
def direct_follower_ids _args={}
|
199
194
|
result = ::Set.new
|
200
195
|
with_follower_candidate_ids do
|
201
196
|
set_names.each do |set_name|
|
@@ -226,7 +221,7 @@ def all_direct_follower_ids_with_reason
|
|
226
221
|
end
|
227
222
|
end
|
228
223
|
|
229
|
-
|
224
|
+
# ~~~~~ cache methods
|
230
225
|
|
231
226
|
def write_follower_ids_cache user_ids
|
232
227
|
hash = Card.follower_ids_cache
|