card 1.16.13 → 1.16.14
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.
- 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) {
|