card 1.16.13 → 1.16.14
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/20150501010515_responsive_sidebar.rb +11 -0
- data/db/schema.rb +1 -1
- data/lib/card/auth.rb +3 -2
- data/lib/card/env.rb +1 -1
- data/lib/card/loader.rb +79 -40
- data/lib/card/query.rb +5 -5
- data/lib/card/query/sql_statement.rb +10 -4
- data/lib/card/query/value.rb +5 -8
- data/lib/card/set.rb +0 -1
- data/lib/cardio.rb +18 -22
- data/mod/01_core/chunk/link.rb +37 -34
- data/mod/01_core/chunk/query_reference.rb +1 -1
- data/mod/01_core/set/all/fetch.rb +66 -58
- data/mod/01_core/set/all/permissions.rb +84 -83
- data/mod/01_core/set/all/templating.rb +6 -5
- data/mod/01_core/set/all/type.rb +16 -14
- data/mod/02_basic_types/set/all/base.rb +3 -3
- data/mod/02_basic_types/set/type/pointer.rb +4 -4
- data/mod/02_basic_types/spec/set/all/base_spec.rb +16 -1
- data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +65 -0
- data/mod/05_email/set/all/follow.rb +6 -10
- data/mod/05_email/set/type/email_template.rb +1 -1
- data/mod/05_standard/lib/file_uploader.rb +39 -41
- data/mod/05_standard/set/all/account.rb +18 -20
- data/mod/05_standard/set/all/rich_html/toolbar.rb +1 -1
- data/mod/05_standard/set/right/account.rb +2 -2
- data/mod/05_standard/set/right/email.rb +14 -13
- data/mod/05_standard/set/right/password.rb +20 -12
- data/mod/05_standard/set/right/status.rb +2 -2
- data/mod/05_standard/set/self/head.rb +66 -53
- data/mod/05_standard/set/type/search_type.rb +3 -2
- data/mod/05_standard/set/type/set.rb +3 -3
- data/mod/06_bootstrap/lib/stylesheets/bootstrap_cards.scss +50 -0
- data/spec/lib/card/query_spec.rb +7 -0
- data/spec/spec_helper.rb +1 -1
- metadata +3 -2
@@ -9,11 +9,11 @@ def account
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def accountable?
|
12
|
-
Card.toggle(
|
12
|
+
Card.toggle(rule :accountable)
|
13
13
|
end
|
14
14
|
|
15
15
|
def parties
|
16
|
-
@parties ||= (all_roles <<
|
16
|
+
@parties ||= (all_roles << id).flatten.reject(&:blank?)
|
17
17
|
end
|
18
18
|
|
19
19
|
def among? ok_ids
|
@@ -23,18 +23,18 @@ def among? ok_ids
|
|
23
23
|
ok_ids.member? Card::AnyoneID
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
26
|
+
def own_account?
|
27
27
|
# card is +*account card of signed_in user.
|
28
|
-
cardname.part_names[0].key == Auth.as_card.key
|
29
|
-
|
28
|
+
cardname.part_names[0].key == Auth.as_card.key &&
|
29
|
+
cardname.part_names[1].key == Card[:account].key
|
30
30
|
end
|
31
31
|
|
32
32
|
def read_rules
|
33
33
|
@read_rules ||= begin
|
34
34
|
rule_ids = []
|
35
|
-
unless id==Card::WagnBotID # always_ok, so not needed
|
36
|
-
(
|
37
|
-
if rule_ids_for_party = self.class.read_rule_cache[
|
35
|
+
unless id == Card::WagnBotID # always_ok, so not needed
|
36
|
+
([Card::AnyoneID] + parties).each do |party_id|
|
37
|
+
if rule_ids_for_party = self.class.read_rule_cache[party_id]
|
38
38
|
rule_ids += rule_ids_for_party
|
39
39
|
end
|
40
40
|
end
|
@@ -44,24 +44,22 @@ def read_rules
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def all_roles
|
47
|
-
@all_roles ||=
|
48
|
-
if id == Card::AnonymousID
|
49
|
-
[]
|
50
|
-
else
|
51
|
-
Auth.as_bot do
|
52
|
-
role_trait = fetch trait: :roles
|
53
|
-
[ Card::AnyoneSignedInID ] + ( role_trait ? role_trait.item_ids : [] )
|
54
|
-
end
|
55
|
-
end
|
47
|
+
@all_roles ||= (id == Card::AnonymousID ? [] : fetch_roles)
|
56
48
|
end
|
57
49
|
|
50
|
+
def fetch_roles
|
51
|
+
Auth.as_bot do
|
52
|
+
role_trait = fetch trait: :roles
|
53
|
+
next [Card::AnyoneSignedInID] unless role_trait
|
54
|
+
[Card::AnyoneSignedInID] + (role_trait.item_ids)
|
55
|
+
end
|
56
|
+
end
|
58
57
|
|
59
58
|
event :generate_token do
|
60
|
-
Digest::SHA1.hexdigest "--#{Time.now.to_f}--#{rand 10}--"
|
59
|
+
Digest::SHA1.hexdigest "--#{Time.zone.now.to_f}--#{rand 10}--"
|
61
60
|
end
|
62
61
|
|
63
62
|
event :set_stamper, before: :approve do
|
64
63
|
self.updater_id = Auth.current_id
|
65
|
-
self.creator_id =
|
64
|
+
self.creator_id = updater_id if new_card?
|
66
65
|
end
|
67
|
-
|
@@ -213,9 +213,9 @@ format :html do
|
|
213
213
|
path_opts = tag_args.delete(:path_opts) || {}
|
214
214
|
path_opts.merge! action: tag_args.delete(:action) if tag_args[:action]
|
215
215
|
link_to link_text, path_opts, tag_args
|
216
|
+
|
216
217
|
end
|
217
218
|
end
|
218
|
-
|
219
219
|
def autosaved_draft_link
|
220
220
|
view_link('autosaved draft', :edit, path_opts: {edit_draft: true, slot: {show: :toolbar}}, class: 'navbar-link slotter pull-right')
|
221
221
|
end
|
@@ -71,7 +71,7 @@ event :require_email, on: :create, after: :approve do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
event :set_default_salt, on: :create, before: :process_subcards do
|
74
|
-
salt = Digest::SHA1.hexdigest "--#{Time.now
|
74
|
+
salt = Digest::SHA1.hexdigest "--#{Time.zone.now}--"
|
75
75
|
Env[:salt] = salt # HACK!!! need viable mechanism to get this to password
|
76
76
|
add_subfield :salt, content: salt
|
77
77
|
end
|
@@ -146,7 +146,7 @@ event :send_reset_password_token do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
def ok_to_read
|
149
|
-
|
149
|
+
own_account? ? true : super
|
150
150
|
end
|
151
151
|
|
152
152
|
def changes_visible? act
|
@@ -1,10 +1,11 @@
|
|
1
|
-
#event :
|
2
1
|
include All::Permissions::Accounts
|
3
2
|
|
4
|
-
view :raw do
|
3
|
+
view :raw do
|
5
4
|
case
|
6
|
-
when card.real?
|
7
|
-
|
5
|
+
when card.real? then card.content
|
6
|
+
# following supports legacy behavior
|
7
|
+
# (should be moved to User+*email+*type plus right)
|
8
|
+
when card.left.account then card.left.account.email
|
8
9
|
else ''
|
9
10
|
end
|
10
11
|
end
|
@@ -22,7 +23,7 @@ event :validate_unique_email, after: :validate_email, on: :save do
|
|
22
23
|
Auth.as_bot do
|
23
24
|
wql = { right_id: Card::EmailID, eq: content }
|
24
25
|
wql[:not] = { id: id } if id
|
25
|
-
if Card.search(
|
26
|
+
if Card.search(wql).first
|
26
27
|
errors.add :content, 'must be unique'
|
27
28
|
end
|
28
29
|
end
|
@@ -30,9 +31,8 @@ event :validate_unique_email, after: :validate_email, on: :save do
|
|
30
31
|
end
|
31
32
|
|
32
33
|
event :downcase_email, before: :approve, on: :save do
|
33
|
-
if content
|
34
|
-
|
35
|
-
end
|
34
|
+
return if !content || content == content.downcase
|
35
|
+
self.content = content.downcase
|
36
36
|
end
|
37
37
|
|
38
38
|
def email_required?
|
@@ -40,13 +40,14 @@ def email_required?
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def ok_to_read
|
43
|
-
if
|
43
|
+
if own_email? || Auth.always_ok?
|
44
44
|
true
|
45
45
|
else
|
46
|
-
deny_because
|
46
|
+
deny_because 'viewing email is restricted to administrators and ' \
|
47
|
+
'account holders'
|
47
48
|
end
|
48
49
|
end
|
49
50
|
|
50
|
-
def
|
51
|
-
cardname.
|
52
|
-
end
|
51
|
+
def own_email?
|
52
|
+
cardname.part_names[0].key == Auth.as_card.key
|
53
|
+
end
|
@@ -1,26 +1,34 @@
|
|
1
1
|
|
2
2
|
include All::Permissions::Accounts
|
3
3
|
|
4
|
-
view :editor do
|
4
|
+
view :editor do
|
5
5
|
card.content = ''
|
6
|
-
|
6
|
+
|
7
|
+
# HACK
|
8
|
+
autocomplete = if @parent && @parent.card.name == '*signin+*account'
|
9
|
+
'on'
|
10
|
+
else
|
11
|
+
'off'
|
12
|
+
end
|
7
13
|
password_field :content, class: 'card-content', autocomplete: autocomplete
|
8
14
|
end
|
9
15
|
|
10
|
-
view :raw do
|
16
|
+
view :raw do
|
11
17
|
'<em>encrypted</em>'
|
12
18
|
end
|
13
19
|
|
14
|
-
event :encrypt_password, on: :save, after: :process_subcards,
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
salt =
|
19
|
-
|
20
|
+
event :encrypt_password, on: :save, after: :process_subcards,
|
21
|
+
changed: :content,
|
22
|
+
when: proc { !Card::Env[:no_password_encryptions] } do
|
23
|
+
# no_password_encryptions = hack for import - fix with api for ignoring events
|
24
|
+
salt = left && left.salt
|
25
|
+
# HACK: fix with better ORM handling
|
26
|
+
salt = Card::Env[:salt] unless salt.present?
|
20
27
|
self.content = Auth.encrypt content, salt
|
21
28
|
|
22
|
-
#
|
23
|
-
#
|
29
|
+
# errors.add :password, 'need a valid salt'
|
30
|
+
# turns out we have a lot of existing account without a salt.
|
31
|
+
# not sure when that broke??
|
24
32
|
end
|
25
33
|
|
26
34
|
event :validate_password, on: :save, before: :approve do
|
@@ -34,5 +42,5 @@ event :validate_password_present, on: :update, before: :approve do
|
|
34
42
|
end
|
35
43
|
|
36
44
|
def ok_to_read
|
37
|
-
|
45
|
+
own_account? ? true : super
|
38
46
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
format :html do
|
2
|
-
|
3
|
-
view :raw do |args|
|
2
|
+
view :raw do
|
4
3
|
%(
|
5
4
|
<meta charset="UTF-8">
|
6
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
@@ -13,79 +12,93 @@ format :html do
|
|
13
12
|
|
14
13
|
view :core do |args|
|
15
14
|
case
|
16
|
-
when focal?
|
17
|
-
when @mainline
|
18
|
-
else
|
15
|
+
when focal? then CGI.escapeHTML _render_raw(args)
|
16
|
+
when @mainline then "(*head)"
|
17
|
+
else _render_raw(args)
|
19
18
|
end
|
20
19
|
end
|
21
20
|
|
22
21
|
def head_title
|
23
22
|
title = root.card && root.card.name
|
24
23
|
title = nil if title.blank?
|
25
|
-
title = params[:action] if title=='*placeholder'
|
24
|
+
title = params[:action] if title == '*placeholder'
|
26
25
|
%(<title>#{title ? "#{title} - " : ''}#{ Card.setting :title }</title>)
|
27
26
|
end
|
28
27
|
|
29
28
|
def head_buttons
|
30
|
-
bits = []
|
31
|
-
[:favicon, :logo].each do |name|
|
32
|
-
if c = Card[name] and c.type_id == ImageID and !c.db_content.blank?
|
33
|
-
bits << %{<link rel="shortcut icon" href="#{ subformat(c)._render_source size: :small }" />}
|
34
|
-
break
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
#Universal Edit Button
|
29
|
+
bits = [favicon]
|
39
30
|
if root.card
|
40
|
-
|
41
|
-
bits << %{<link rel="alternate" type="application/x-wiki" title="Edit this page!" href="#{ root.path view: :edit }"/>}
|
42
|
-
end
|
43
|
-
|
31
|
+
bits << universal_edit_button
|
44
32
|
# RSS # move to mods!
|
45
33
|
if root.card.type_id == SearchTypeID
|
46
|
-
|
47
|
-
root.search_params[:vars].each { |key, val| opts["_#{key}"] = val }
|
48
|
-
bits << %{<link rel="alternate" type="application/rss+xml" title="RSS" href=#{page_path root.card.cardname, opts} />}
|
34
|
+
bits << rss_link
|
49
35
|
end
|
50
36
|
end
|
51
|
-
bits.join "\n "
|
37
|
+
bits.compact.join "\n "
|
38
|
+
end
|
39
|
+
|
40
|
+
def favicon
|
41
|
+
[:favicon, :logo].each do |name|
|
42
|
+
if (c = Card[name]) && c.type_id == ImageID && !c.db_content.blank?
|
43
|
+
href = subformat(c)._render_source size: :small
|
44
|
+
return %{<link rel="shortcut icon" href="#{ href }" />}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def universal_edit_button
|
50
|
+
return if root.card.new_record? || !root.card.ok?(:update)
|
51
|
+
href = root.path view: :edit
|
52
|
+
%{<link rel="alternate" type="application/x-wiki" title="Edit this page!" href="#{ href }"/>}
|
53
|
+
end
|
54
|
+
|
55
|
+
def rss_link
|
56
|
+
opts = { format: :rss }
|
57
|
+
root.search_params[:vars].each { |key, val| opts["_#{key}"] = val }
|
58
|
+
href = page_path root.card.cardname, opts
|
59
|
+
%{<link rel="alternate" type="application/rss+xml" title="RSS" href="#{href}" />}
|
52
60
|
end
|
53
61
|
|
54
62
|
def head_stylesheets
|
55
63
|
manual_style = params[:style]
|
56
|
-
style_card
|
64
|
+
style_card = Card[manual_style] if manual_style
|
57
65
|
style_card ||= root.card.rule_card :style
|
58
|
-
@css_path =
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
end
|
66
|
+
@css_path =
|
67
|
+
if params[:debug] == 'style'
|
68
|
+
page_path(style_card.cardname, item: :import, format: :css)
|
69
|
+
elsif style_card
|
70
|
+
card_path style_card.machine_output_url
|
71
|
+
end
|
72
|
+
return unless @css_path
|
73
|
+
%{<link href="#{@css_path}" media="all" rel="stylesheet" type="text/css" />}
|
67
74
|
end
|
68
75
|
|
69
76
|
def head_javascript
|
70
77
|
varvals = [
|
71
78
|
"window.wagn={rootPath:'#{ Card.config.relative_url_root }'}",
|
72
|
-
|
79
|
+
# tinyMCE doesn't load on non-root wagns w/o preinit line
|
80
|
+
"window.tinyMCEPreInit={base:\"#{card_path 'assets/tinymce'}\",query:'3.5.9',suffix:''}"
|
73
81
|
]
|
74
|
-
card.have_recaptcha_keys?
|
75
|
-
|
76
|
-
|
82
|
+
card.have_recaptcha_keys? &&
|
83
|
+
varvals << "wagn.recaptchaKey='#{Card.config.recaptcha_public_key}'"
|
84
|
+
(c = Card[:double_click]) && !Card.toggle(c.content) &&
|
85
|
+
varvals << 'wagn.noDoubleClick=true'
|
86
|
+
@css_path &&
|
87
|
+
varvals << "wagn.cssPath='#{@css_path}'"
|
77
88
|
|
78
89
|
manual_script = params[:script]
|
79
90
|
script_card = Card[manual_script] if manual_script
|
80
91
|
script_card ||= root.card.rule_card :script
|
81
92
|
|
82
|
-
@js_tag =
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
93
|
+
@js_tag =
|
94
|
+
if params[:debug] == 'script'
|
95
|
+
script_card.format(:js).render_core item: :include_tag
|
96
|
+
elsif script_card
|
97
|
+
javascript_include_tag script_card.machine_output_url
|
98
|
+
end
|
99
|
+
ie9_card = Card[:script_html5shiv_printshiv]
|
100
|
+
<<-HTML
|
101
|
+
#{ javascript_tag do varvals * ';' end }
|
89
102
|
#{ @js_tag if @js_tag }
|
90
103
|
<!--[if lt IE 9]>#{ javascript_include_tag ie9_card.machine_output_url if ie9_card }<![endif]-->
|
91
104
|
#{ javascript_tag { "wagn.setTinyMCEConfig('#{ escape_javascript Card.setting(:tiny_mce).to_s }')" } }
|
@@ -94,26 +107,26 @@ format :html do
|
|
94
107
|
$('document').ready(function() {
|
95
108
|
$('.card-slot').trigger('slotReady');
|
96
109
|
})
|
97
|
-
</script>
|
110
|
+
</script>
|
111
|
+
HTML
|
98
112
|
end
|
99
113
|
|
100
|
-
|
101
114
|
def google_analytics_head_javascript
|
102
|
-
if ga_key = Card.setting("*google analytics key") #
|
103
|
-
|
115
|
+
if (ga_key = Card.setting("*google analytics key")) # FIXME: escape this?
|
116
|
+
<<-HTML
|
104
117
|
<script type="text/javascript">
|
105
118
|
var _gaq = _gaq || [];
|
106
119
|
_gaq.push(['_setAccount', '#{ga_key}']);
|
107
120
|
_gaq.push(['_trackPageview']);
|
108
121
|
(function() {
|
109
|
-
var ga = document.createElement('script');
|
122
|
+
var ga = document.createElement('script');
|
123
|
+
ga.type = 'text/javascript'; ga.async = true;
|
110
124
|
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
111
|
-
var s = document.getElementsByTagName('script')[0];
|
125
|
+
var s = document.getElementsByTagName('script')[0];
|
126
|
+
s.parentNode.insertBefore(ga, s);
|
112
127
|
})();
|
113
128
|
</script>
|
114
|
-
|
129
|
+
HTML
|
115
130
|
end
|
116
131
|
end
|
117
132
|
end
|
118
|
-
|
119
|
-
|
@@ -4,11 +4,12 @@ def item_cards params={}
|
|
4
4
|
raise('OH NO.. no limit') unless s[:limit]
|
5
5
|
# forces explicit limiting
|
6
6
|
# can be 0 or less to force no limit
|
7
|
-
|
7
|
+
Query.run(s, name)
|
8
8
|
end
|
9
9
|
|
10
10
|
def item_names params={}
|
11
|
-
|
11
|
+
statement = query params.merge(return: :name)
|
12
|
+
Query.run(statement, name)
|
12
13
|
end
|
13
14
|
|
14
15
|
def item_type
|
@@ -227,13 +227,13 @@ def junction_only?()
|
|
227
227
|
end
|
228
228
|
|
229
229
|
def reset_set_patterns
|
230
|
-
Card.
|
230
|
+
Card.cached_set_members(key).each do |mem|
|
231
231
|
Card.expire mem
|
232
232
|
end
|
233
233
|
end
|
234
234
|
|
235
235
|
def label
|
236
|
-
if klass = subclass_for_set
|
236
|
+
if (klass = subclass_for_set)
|
237
237
|
klass.label cardname.left
|
238
238
|
else
|
239
239
|
''
|
@@ -241,7 +241,7 @@ def label
|
|
241
241
|
end
|
242
242
|
|
243
243
|
def follow_label
|
244
|
-
if klass = subclass_for_set
|
244
|
+
if (klass = subclass_for_set)
|
245
245
|
klass.follow_label cardname.left
|
246
246
|
else
|
247
247
|
''
|
@@ -82,6 +82,56 @@ body.mceContentBody {
|
|
82
82
|
}
|
83
83
|
|
84
84
|
|
85
|
+
/*----------- Sidebar -------------*/
|
86
|
+
|
87
|
+
.row.row-offcanvas {
|
88
|
+
> aside, article {
|
89
|
+
margin: 0;
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
/* collapsed sidebar styles */
|
94
|
+
@media screen and (max-width: 767px) {
|
95
|
+
.row-offcanvas {
|
96
|
+
position: relative;
|
97
|
+
-webkit-transition: all 0.25s ease-out;
|
98
|
+
-moz-transition: all 0.25s ease-out;
|
99
|
+
transition: all 0.25s ease-out;
|
100
|
+
}
|
101
|
+
|
102
|
+
.sidebar-offcanvas-right {
|
103
|
+
right: -41.6%;
|
104
|
+
}
|
105
|
+
|
106
|
+
.sidebar-offcanvas-left {
|
107
|
+
left: -41.6%;
|
108
|
+
}
|
109
|
+
.row-offcanvas.right-active {
|
110
|
+
right: 41.6%;
|
111
|
+
}
|
112
|
+
.row-offcanvas.left-active {
|
113
|
+
left: 41.6%;
|
114
|
+
}
|
115
|
+
.sidebar-offcanvas {
|
116
|
+
position: absolute !important;
|
117
|
+
top: 0 !important;
|
118
|
+
width: 41.6% !important;
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
.offcanvas-toggle {
|
123
|
+
font-size: 10px !important;
|
124
|
+
padding: 5px !important;
|
125
|
+
margin-bottom: 15px !important;
|
126
|
+
}
|
127
|
+
.offcanvas-toggle-right {
|
128
|
+
float: right;
|
129
|
+
}
|
130
|
+
.offcanvas-toggle-left {
|
131
|
+
float: left;
|
132
|
+
}
|
133
|
+
|
134
|
+
|
85
135
|
/*---------- Card menu ------------*/
|
86
136
|
|
87
137
|
@media (min-width: $screen-xs-max) {
|