card 1.15.4 → 1.15.5
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/config/initializers/recaptcha.rb +1 -1
- data/db/migrate_core_cards/20141208162106_add_ace_script.rb +2 -4
- data/db/migrate_core_cards/20150508212032_menu_compatibility.rb +1 -2
- data/db/migrate_core_cards/20150605115802_add_performance_log_card.rb +7 -0
- data/lib/card/content.rb +6 -0
- data/lib/card/log.rb +110 -17
- data/lib/card/query.rb +31 -21
- data/lib/cardio.rb +1 -0
- data/mod/01_core/set/all/collection.rb +42 -8
- data/mod/01_core/set/all/permissions.rb +21 -21
- data/mod/01_core/set/all/templating.rb +18 -12
- data/mod/01_core/spec/set/all/collection_spec.rb +7 -1
- data/mod/01_history/set/all/content_history.rb +14 -12
- data/mod/02_basic_types/set/type/pointer.rb +54 -24
- data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +1 -1
- data/mod/03_machines/lib/stylesheets/style_cards.scss +3 -0
- data/mod/03_machines/set/type/scss.rb +5 -5
- data/mod/05_email/set/right/follow.rb +3 -3
- data/mod/05_standard/set/all/rich_html/content.rb +17 -13
- data/mod/05_standard/set/self/performance_log.rb +92 -0
- data/mod/05_standard/set/type/search_type.rb +15 -17
- data/spec/lib/card/content_spec.rb +12 -0
- metadata +4 -17
- data/db/seed/README.md +0 -2
- data/db/seed/new/card_actions.yml +0 -4495
- data/db/seed/new/card_acts.yml +0 -7
- data/db/seed/new/card_changes.yml +0 -29416
- data/db/seed/new/card_references.yml +0 -4348
- data/db/seed/new/cards.yml +0 -28134
- data/db/seed/test/fixtures/.gitkeep +0 -0
- data/db/seed/test/fixtures/card_actions.yml +0 -6336
- data/db/seed/test/fixtures/card_acts.yml +0 -841
- data/db/seed/test/fixtures/card_changes.yml +0 -34632
- data/db/seed/test/fixtures/card_references.yml +0 -5783
- data/db/seed/test/fixtures/cards.yml +0 -32803
- data/db/seed/test/fixtures/mao2.jpg +0 -0
- data/db/seed/test/fixtures/rails.gif +0 -0
- data/db/seed/test/seed.rb +0 -201
@@ -1,5 +1,5 @@
|
|
1
1
|
|
2
|
-
Card.error_codes.merge! :permission_denied=>[:denial, 403], :captcha=>[:
|
2
|
+
Card.error_codes.merge! :permission_denied=>[:denial, 403], :captcha=>[:errors,449]
|
3
3
|
|
4
4
|
|
5
5
|
# ok? and ok! are public facing methods to approve one action at a time
|
@@ -36,7 +36,7 @@ end
|
|
36
36
|
|
37
37
|
def permission_rule_card action
|
38
38
|
opcard = rule_card action
|
39
|
-
|
39
|
+
|
40
40
|
unless opcard # RULE missing. should not be possible. generalize this to handling of all required rules
|
41
41
|
errors.add :permission_denied, "No #{action} rule for #{name}"
|
42
42
|
raise Card::PermissionDenied.new(self)
|
@@ -90,7 +90,7 @@ def permit action, verb=nil
|
|
90
90
|
if Card.config.read_only # not called by ok_to_read
|
91
91
|
deny_because "Currently in read-only mode"
|
92
92
|
end
|
93
|
-
|
93
|
+
|
94
94
|
verb ||= action.to_s
|
95
95
|
unless permitted? action
|
96
96
|
deny_because you_cant("#{verb} #{name.present? ? name : 'this'}")
|
@@ -102,7 +102,7 @@ def ok_to_create
|
|
102
102
|
if @action_ok and junction?
|
103
103
|
[:left, :right].each do |side|
|
104
104
|
next if side==:left && @superleft # left is supercard; create permissions will get checked there.
|
105
|
-
part_card = send side, :new=>{}
|
105
|
+
part_card = send side, :new=>{}
|
106
106
|
if part_card && part_card.new_card? # if no card, there must be other errors
|
107
107
|
unless part_card.ok? :create
|
108
108
|
deny_because you_cant("create #{part_card.name}")
|
@@ -199,7 +199,7 @@ event :check_permissions, :after=>:approve do
|
|
199
199
|
else
|
200
200
|
@action
|
201
201
|
end
|
202
|
-
|
202
|
+
|
203
203
|
track_permission_errors do
|
204
204
|
ok? task
|
205
205
|
end
|
@@ -208,12 +208,12 @@ end
|
|
208
208
|
def track_permission_errors
|
209
209
|
@permission_errors = []
|
210
210
|
result = yield
|
211
|
-
|
211
|
+
|
212
212
|
@permission_errors.each do |message|
|
213
213
|
errors.add :permission_denied, message
|
214
214
|
end
|
215
215
|
@permission_errors = nil
|
216
|
-
|
216
|
+
|
217
217
|
result
|
218
218
|
end
|
219
219
|
|
@@ -224,16 +224,16 @@ def recaptcha_on?
|
|
224
224
|
!Auth.signed_in? &&
|
225
225
|
!Auth.needs_setup? &&
|
226
226
|
!Auth.always_ok? &&
|
227
|
-
Card.toggle( rule :captcha )
|
227
|
+
Card.toggle( rule :captcha )
|
228
228
|
end
|
229
229
|
|
230
230
|
def have_recaptcha_keys?
|
231
|
-
@@have_recaptcha_keys = defined?(@@have_recaptcha_keys) ? @@have_recaptcha_keys :
|
231
|
+
@@have_recaptcha_keys = defined?(@@have_recaptcha_keys) ? @@have_recaptcha_keys :
|
232
232
|
!!( Card.config.recaptcha_public_key && Card.config.recaptcha_private_key )
|
233
233
|
end
|
234
234
|
|
235
235
|
event :recaptcha, :before=>:approve do
|
236
|
-
if !@supercard && !Env[:recaptcha_used] && recaptcha_on?
|
236
|
+
if !@supercard && !Env[:recaptcha_used] && recaptcha_on?
|
237
237
|
Env[:recaptcha_used] = true
|
238
238
|
Env[:controller].verify_recaptcha :model=>self, :attribute=>:captcha
|
239
239
|
end
|
@@ -242,43 +242,43 @@ end
|
|
242
242
|
module Accounts
|
243
243
|
# This is a short-term hack that is used in account-related cards to allow a permissions pattern where
|
244
244
|
# permissions are restricted to the owner of the account (and, by default, Admin)
|
245
|
-
# That pattern should be permitted by our card representation (without creating
|
245
|
+
# That pattern should be permitted by our card representation (without creating
|
246
246
|
# separate rules for each account holder) but is not yet.
|
247
|
-
|
247
|
+
|
248
248
|
def permit action, verb=nil
|
249
249
|
case
|
250
250
|
when action==:comment ; @action_ok = false
|
251
|
-
when action==:create ; @superleft ? true : super( action, verb )
|
251
|
+
when action==:create ; @superleft ? true : super( action, verb )
|
252
252
|
#restricts account creation to subcard handling on permitted card (unless explicitly permitted)
|
253
253
|
when is_own_account? ; true
|
254
254
|
else ; super action, verb
|
255
255
|
end
|
256
256
|
end
|
257
|
-
|
257
|
+
|
258
258
|
end
|
259
259
|
|
260
|
-
module Follow
|
260
|
+
module Follow
|
261
261
|
def ok_to_update
|
262
262
|
permit :update
|
263
263
|
end
|
264
|
-
|
264
|
+
|
265
265
|
def ok_to_create
|
266
266
|
permit :create
|
267
267
|
end
|
268
|
-
|
268
|
+
|
269
269
|
def ok_to_delete
|
270
270
|
permit :delete
|
271
271
|
end
|
272
|
-
|
272
|
+
|
273
273
|
def permit action, verb=nil
|
274
|
-
if [:create, :delete, :update].include?(action) && Auth.signed_in? &&
|
274
|
+
if [:create, :delete, :update].include?(action) && Auth.signed_in? &&
|
275
275
|
(user = rule_user) && Auth.current_id == user.id
|
276
276
|
return true
|
277
277
|
else
|
278
278
|
super action, verb
|
279
279
|
end
|
280
280
|
end
|
281
|
-
|
281
|
+
|
282
282
|
end
|
283
|
-
|
283
|
+
|
284
284
|
|
@@ -12,29 +12,34 @@ def template
|
|
12
12
|
# note that a *default template is never returned for an existing card.
|
13
13
|
@template ||= begin
|
14
14
|
@virtual = false
|
15
|
+
|
16
|
+
# NEW CARDS
|
15
17
|
if new_card?
|
16
|
-
|
18
|
+
default = rule_card :default, :skip_modules=>true
|
17
19
|
|
18
20
|
dup_card = dup
|
19
|
-
dup_card.type_id =
|
20
|
-
|
21
|
+
dup_card.type_id = default ? default.type_id : Card.default_type_id
|
21
22
|
|
22
|
-
if
|
23
|
+
if structure = dup_card.structure_rule_card
|
23
24
|
@virtual = true if junction?
|
24
|
-
|
25
|
+
self.type_id = structure.type_id if assign_type_to?(structure)
|
26
|
+
structure
|
25
27
|
else
|
26
|
-
|
27
|
-
end
|
28
|
-
elsif tmpl = structure_rule_card
|
29
|
-
# this is a mechanism for repairing bad data. like #repair_key, it should be obviated and removed.
|
30
|
-
if type_id != tmpl.type_id and tmpl.assigns_type?
|
31
|
-
repair_type tmpl.type_id
|
28
|
+
default
|
32
29
|
end
|
33
|
-
|
30
|
+
|
31
|
+
# EXISTING CARDS
|
32
|
+
elsif structure = structure_rule_card
|
33
|
+
repair_type structure.type_id if assign_type_to?(structure)
|
34
|
+
structure
|
34
35
|
end
|
35
36
|
end
|
36
37
|
end
|
37
38
|
|
39
|
+
def assign_type_to? structure
|
40
|
+
type_id != structure.type_id and structure.assigns_type?
|
41
|
+
end
|
42
|
+
|
38
43
|
def structure
|
39
44
|
if template && template.is_structure?
|
40
45
|
template
|
@@ -102,6 +107,7 @@ end
|
|
102
107
|
private
|
103
108
|
|
104
109
|
def repair_type template_type_id
|
110
|
+
# this is a mechanism for repairing bad data. like #repair_key, it should be obviated and removed.
|
105
111
|
self.type_id = template_type_id
|
106
112
|
update_column :type_id, type_id
|
107
113
|
reset_patterns
|
@@ -94,6 +94,12 @@ describe Card::Set::All::Collection do
|
|
94
94
|
assert_select "li > a[data-toggle=tab][data-url=#{path}]"
|
95
95
|
end
|
96
96
|
end
|
97
|
-
|
97
|
+
it 'handles nests as items' do
|
98
|
+
tabs = render_card :tabs, :name=>'tab_test', :type_id=>Card::PlainTextID, :content=>"{{A|type;title:my tab title}}"
|
99
|
+
assert_view_select tabs, 'div[role=tabpanel]' do
|
100
|
+
assert_select 'li > a[data-toggle=tab][href=#tab_test-a]', 'my tab title'
|
101
|
+
assert_select 'div.tab-pane#tab_test-a', 'Basic'
|
102
|
+
end
|
103
|
+
end
|
98
104
|
end
|
99
105
|
end
|
@@ -26,23 +26,23 @@ end
|
|
26
26
|
def last_change_on(field, opts={})
|
27
27
|
where_sql = 'card_actions.card_id = :card_id AND field = :field AND (draft is not true) '
|
28
28
|
where_sql += if opts[:before]
|
29
|
-
'AND card_action_id < :action_id'
|
29
|
+
'AND card_action_id < :action_id'
|
30
30
|
elsif opts[:not_after]
|
31
31
|
'AND card_action_id <= :action_id'
|
32
32
|
else
|
33
33
|
''
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
action_arg = opts[:before] || opts[:not_after]
|
37
37
|
action_id = action_arg.kind_of?(Card::Action) ? action_arg.id : action_arg
|
38
38
|
field_index = Card::TRACKED_FIELDS.index(field.to_s)
|
39
|
-
Change.joins(:action).where( where_sql,
|
39
|
+
Change.joins(:action).where( where_sql,
|
40
40
|
{:card_id=>id, :field=>field_index, :action_id=>action_id}
|
41
41
|
).order(:id).last
|
42
42
|
end
|
43
43
|
|
44
44
|
def selected_action_id
|
45
|
-
@selected_action_id || (@current_action and @current_action.id) || last_action_id
|
45
|
+
@selected_action_id || (@current_action and @current_action.id) || last_action_id
|
46
46
|
end
|
47
47
|
|
48
48
|
def selected_action_id= action_id
|
@@ -55,9 +55,9 @@ def selected_action
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def selected_content_action_id
|
58
|
-
@selected_action_id ||
|
59
|
-
(@current_action and @current_action.new_content? and @current_action.id) ||
|
60
|
-
last_content_action_id
|
58
|
+
@selected_action_id ||
|
59
|
+
(@current_action and @current_action.new_content? and @current_action.id) ||
|
60
|
+
last_content_action_id
|
61
61
|
end
|
62
62
|
|
63
63
|
def last_action_id
|
@@ -81,11 +81,13 @@ def last_actor
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def last_act
|
84
|
-
|
85
|
-
|
86
|
-
last_act_on_self
|
87
|
-
|
88
|
-
|
84
|
+
if action = last_action
|
85
|
+
last_act_on_self = acts.last
|
86
|
+
if last_act_on_self and ( action.act==last_act_on_self || last_act_on_self.acted_at>action.act.acted_at )
|
87
|
+
last_act_on_self
|
88
|
+
else
|
89
|
+
action.act
|
90
|
+
end
|
89
91
|
end
|
90
92
|
end
|
91
93
|
|
@@ -61,12 +61,12 @@ format :html do
|
|
61
61
|
args ||= {}
|
62
62
|
items = args[:item_list] || card.item_names(:context=>:raw)
|
63
63
|
items = [''] if items.empty?
|
64
|
-
options_card_name = (oc = card.
|
64
|
+
options_card_name = (oc = card.options_rule_card) ? oc.cardname.url_key : ':all'
|
65
65
|
|
66
66
|
extra_css_class = args[:extra_css_class] || 'pointer-list-ul'
|
67
67
|
|
68
68
|
%{
|
69
|
-
<ul class="pointer-list-editor #{extra_css_class}" options-card="#{options_card_name}">
|
69
|
+
<ul class="pointer-list-editor #{extra_css_class}" data-options-card="#{options_card_name}">
|
70
70
|
#{
|
71
71
|
items.map do |item|
|
72
72
|
_render_list_item args.merge( :pointer_item=>item )
|
@@ -106,14 +106,15 @@ format :html do
|
|
106
106
|
|
107
107
|
|
108
108
|
view :checkbox do |args|
|
109
|
-
options = card.
|
110
|
-
checked = card.item_names.include?(
|
111
|
-
|
112
|
-
|
109
|
+
options = card.option_names.map do |option_name|
|
110
|
+
checked = card.item_names.include?(option_name)
|
111
|
+
label = ((o_card = Card.fetch(option_name)) && o_card.label) || option_name
|
112
|
+
id = "pointer-checkbox-#{option_name.to_name.key}"
|
113
|
+
description = pointer_option_description option_name
|
113
114
|
%{
|
114
115
|
<div class="pointer-checkbox">
|
115
|
-
#{ check_box_tag "pointer_checkbox",
|
116
|
-
<label for="#{id}">#{
|
116
|
+
#{ check_box_tag "pointer_checkbox", option_name, checked, :id=>id, :class=>'pointer-checkbox-button' }
|
117
|
+
<label for="#{id}">#{label}</label>
|
117
118
|
#{ %{<div class="checkbox-option-description">#{ description }</div>} if description }
|
118
119
|
</div>
|
119
120
|
}
|
@@ -123,21 +124,23 @@ format :html do
|
|
123
124
|
end
|
124
125
|
|
125
126
|
view :multiselect do |args|
|
126
|
-
|
127
|
-
|
128
|
-
|
127
|
+
select_tag("pointer_multiselect",
|
128
|
+
options_for_select(card.option_names, card.item_names),
|
129
|
+
:multiple=>true, :class=>'pointer-multiselect form-control'
|
130
|
+
)
|
129
131
|
end
|
130
132
|
|
131
133
|
view :radio do |args|
|
132
134
|
input_name = "pointer_radio_button-#{card.key}"
|
133
|
-
options = card.
|
134
|
-
checked = (
|
135
|
-
id = "pointer-radio-#{
|
136
|
-
|
135
|
+
options = card.option_names.map do |option_name|
|
136
|
+
checked = (option_name==card.item_names.first)
|
137
|
+
id = "pointer-radio-#{option_name.to_name.key}"
|
138
|
+
label = ((o_card = Card.fetch(option_name)) && o_card.label) || option_name
|
139
|
+
description = pointer_option_description option_name
|
137
140
|
%{
|
138
141
|
<li class="pointer-radio radio">
|
139
|
-
#{ radio_button_tag input_name,
|
140
|
-
<label for="#{id}">#{
|
142
|
+
#{ radio_button_tag input_name, option_name, checked, :id=>id, :class=>'pointer-radio-button' }
|
143
|
+
<label for="#{id}">#{ label }</label>
|
141
144
|
#{ %{<div class="radio-option-description">#{ description }</div>} if description }
|
142
145
|
</li>
|
143
146
|
}
|
@@ -147,14 +150,17 @@ format :html do
|
|
147
150
|
end
|
148
151
|
|
149
152
|
view :select do |args|
|
150
|
-
options = [["-- Select --",""]] + card.
|
151
|
-
select_tag("pointer_select",
|
153
|
+
options = [["-- Select --",""]] + card.option_names.map{ |x| [x,x]}
|
154
|
+
select_tag("pointer_select",
|
155
|
+
options_for_select(options, card.item_names.first),
|
156
|
+
:class=>'pointer-select form-control'
|
157
|
+
)
|
152
158
|
end
|
153
159
|
|
154
160
|
|
155
161
|
def pointer_option_description option
|
156
162
|
pod_name = card.rule(:options_label) || 'description'
|
157
|
-
dcard = Card[ "#{option
|
163
|
+
dcard = Card[ "#{option}+#{pod_name}" ]
|
158
164
|
if dcard and dcard.ok? :read
|
159
165
|
with_inclusion_mode :normal do
|
160
166
|
subformat(dcard).render_core
|
@@ -255,7 +261,7 @@ def item_ids args={}
|
|
255
261
|
end
|
256
262
|
|
257
263
|
def item_type
|
258
|
-
opt =
|
264
|
+
opt = options_rule_card
|
259
265
|
if !opt or opt==self #fixme, need better recursion prevention
|
260
266
|
nil
|
261
267
|
else
|
@@ -283,6 +289,10 @@ def add_item name
|
|
283
289
|
self.content="[[#{(item_names << name).reject(&:blank?)*"]]\n[["}]]"
|
284
290
|
end
|
285
291
|
end
|
292
|
+
def add_item! name
|
293
|
+
add_item name
|
294
|
+
save!
|
295
|
+
end
|
286
296
|
|
287
297
|
def drop_item name
|
288
298
|
if include_item? name
|
@@ -291,6 +301,10 @@ def drop_item name
|
|
291
301
|
self.content = new_names.empty? ? '' : "[[#{new_names * "]]\n[["}]]"
|
292
302
|
end
|
293
303
|
end
|
304
|
+
def drop_item! name
|
305
|
+
drop_item name
|
306
|
+
save!
|
307
|
+
end
|
294
308
|
|
295
309
|
def insert_item index, name
|
296
310
|
new_names = item_names
|
@@ -298,14 +312,30 @@ def insert_item index, name
|
|
298
312
|
new_names.insert(index,name)
|
299
313
|
self.content = new_names.map { |name| "[[#{name}]]" }.join "\n"
|
300
314
|
end
|
315
|
+
def insert_item! index, name
|
316
|
+
insert_item index, name
|
317
|
+
save!
|
318
|
+
end
|
301
319
|
|
302
320
|
|
303
|
-
def
|
321
|
+
def options_rule_card
|
304
322
|
self.rule_card :options
|
305
323
|
end
|
306
324
|
|
307
|
-
def
|
308
|
-
result_cards = if oc =
|
325
|
+
def option_names
|
326
|
+
result_cards = if oc = options_rule_card
|
327
|
+
oc.item_names :default_limit=>50, :context=>name
|
328
|
+
else
|
329
|
+
Card.search :sort=>'name', :limit=>50, :return=>:name
|
330
|
+
end
|
331
|
+
if selected_options = item_names
|
332
|
+
result_cards = result_cards | selected_options
|
333
|
+
end
|
334
|
+
result_cards
|
335
|
+
end
|
336
|
+
|
337
|
+
def option_cards
|
338
|
+
result_cards = if oc = options_rule_card
|
309
339
|
oc.item_cards :default_limit=>50, :context=>name
|
310
340
|
else
|
311
341
|
Card.search :sort=>'alpha', :limit=>50
|
@@ -25,7 +25,7 @@ $.extend wagn,
|
|
25
25
|
}
|
26
26
|
|
27
27
|
initPointerList: (input)->
|
28
|
-
optionsCard = input.closest('ul').
|
28
|
+
optionsCard = input.closest('ul').data('options-card')
|
29
29
|
input.autocomplete { source: wagn.prepUrl wagn.rootPath + '/' + optionsCard + '.json?view=name_complete' }
|
30
30
|
|
31
31
|
setTinyMCEConfig: (string)->
|
@@ -2,21 +2,21 @@ include Type::Css
|
|
2
2
|
|
3
3
|
def diff_args
|
4
4
|
{:format=>:text}
|
5
|
-
end
|
5
|
+
end
|
6
6
|
|
7
7
|
format do
|
8
8
|
include Css::Format
|
9
|
-
|
9
|
+
|
10
10
|
view :core do |args|
|
11
11
|
compile_scss(process_content _render_raw)
|
12
12
|
end
|
13
|
-
|
13
|
+
|
14
14
|
def compile_scss scss, style=:expanded
|
15
15
|
Sass.compile scss, :style=>style
|
16
16
|
rescue =>e
|
17
17
|
e
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
end
|
21
21
|
|
22
|
-
format( :html ) { include Css::HtmlFormat }
|
22
|
+
format( :html ) { include Css::HtmlFormat }
|