card 1.101.0 → 1.101.1
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/locales/en.yml +9 -6
- data/db/migrate_core_cards/data/decko_logo.svg +1 -59
- data/lib/card.rb +3 -0
- data/lib/card/content/diff/result.rb +40 -29
- data/lib/card/env.rb +2 -2
- data/lib/card/model/save_helper.rb +16 -182
- data/lib/card/model/save_helper/save_arguments.rb +94 -0
- data/lib/card/model/save_helper/save_helper_helper.rb +93 -0
- data/lib/card/name/all.rb +125 -0
- data/lib/card/name/all/class_methods.rb +28 -0
- data/lib/card/name/all/descendants.rb +46 -0
- data/lib/card/name/all/parts.rb +67 -0
- data/lib/card/query.rb +7 -2
- data/lib/card/query/card_query/interpretation.rb +2 -2
- data/lib/card/query/card_query/sorting.rb +12 -4
- data/lib/card/query/sql_statement.rb +1 -1
- data/lib/card/set/advanced_api.rb +8 -5
- data/lib/card/set/event/options.rb +13 -5
- data/lib/card/set/format.rb +16 -9
- data/lib/card/set/trait.rb +11 -8
- data/lib/card/subcards/add.rb +3 -24
- data/lib/card/subcards/args.rb +42 -0
- data/lib/card/tasks/card/file_card_creator/output_helper.rb +15 -10
- data/lib/card/view/options.rb +2 -1
- data/lib/card/view/permission.rb +14 -3
- data/lib/cardio.rb +9 -66
- data/lib/cardio/defaults.yml +70 -0
- data/lib/cardio/migration.rb +1 -1
- data/mod/core/set/all/assign_attributes.rb +8 -21
- data/mod/core/set/all/initialize.rb +9 -9
- data/mod/core/set/all/name_events.rb +3 -1
- data/mod/core/set/all/references.rb +2 -2
- data/mod/{settings → core}/set/right/autoname.rb +0 -0
- data/mod/{settings → core}/set/self/autoname.rb +0 -0
- data/mod/core/set/type/cardtype.rb +28 -0
- data/mod/{standard → core}/spec/set/type/cardtype_spec.rb +3 -24
- data/mod/standard/file/logo/image-original.svg +1 -59
- metadata +16 -27
- data/config/initializers/uuid_state_file.rb +0 -3
- data/mod/Modfile +0 -4
- data/mod/core/set/all/name.rb +0 -229
- data/mod/core/spec/set/all/name_spec.rb +0 -11
- data/mod/standard/set/all/rich_html/html_views/info.rb +0 -84
- data/mod/standard/set/type/cardtype.rb +0 -119
data/lib/card/query.rb
CHANGED
@@ -37,12 +37,13 @@ class Card
|
|
37
37
|
require "card/query/clause"
|
38
38
|
require "card/query/card_query"
|
39
39
|
require "card/query/sql_statement"
|
40
|
+
|
40
41
|
# Card::Query::CardQuery
|
41
|
-
# After conversion,
|
42
|
+
# After conversion, @attributes is a Hash where the key is the attribute
|
42
43
|
# and the value is the attribute type:
|
43
44
|
# { id: :basic, name: :basic, key: :basic ...}
|
44
45
|
# This is used for rapid attribute type lookups in the interpretation phase.
|
45
|
-
|
46
|
+
@attributes = {
|
46
47
|
# Each of the "basic" fields corresponds directly to a database field.
|
47
48
|
# their values are translated fairly directly into SQL-safe values.
|
48
49
|
# (These are referred to as "properties" in CQL documentation. Need to
|
@@ -87,6 +88,8 @@ class Card
|
|
87
88
|
DEFAULT_ORDER_DIRS = { update: "desc", relevance: "desc" }.freeze
|
88
89
|
|
89
90
|
class << self
|
91
|
+
attr_accessor :attributes
|
92
|
+
|
90
93
|
def new statement, comment=nil
|
91
94
|
Query::CardQuery.new statement, comment
|
92
95
|
end
|
@@ -106,5 +109,7 @@ class Card
|
|
106
109
|
txt
|
107
110
|
end
|
108
111
|
end
|
112
|
+
|
113
|
+
delegate :attributes, to: :class
|
109
114
|
end
|
110
115
|
end
|
@@ -29,7 +29,7 @@ class Card
|
|
29
29
|
def interpret_as_content? key
|
30
30
|
# eg "match" is both operator and attribute;
|
31
31
|
# interpret as attribute when "match" is key
|
32
|
-
OPERATORS.key?(key.to_s) && !
|
32
|
+
OPERATORS.key?(key.to_s) && !Query.attributes[key]
|
33
33
|
end
|
34
34
|
|
35
35
|
def interpret_as_modifier? key, val
|
@@ -43,7 +43,7 @@ class Card
|
|
43
43
|
end
|
44
44
|
|
45
45
|
def interpret_attributes attribute, val
|
46
|
-
attribute_type =
|
46
|
+
attribute_type = Query.attributes[attribute]
|
47
47
|
if (method = INTERPRET_METHOD[attribute_type])
|
48
48
|
send method, attribute, val
|
49
49
|
else
|
@@ -16,10 +16,9 @@ class Card
|
|
16
16
|
def sort val
|
17
17
|
return nil unless full?
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
sort_by val, item, sort_field
|
19
|
+
interpret_sort_hash val do |value, item, sort_field|
|
20
|
+
sort_by value, item, sort_field
|
21
|
+
end
|
23
22
|
end
|
24
23
|
|
25
24
|
def sort_by val, item, sort_field
|
@@ -95,6 +94,15 @@ class Card
|
|
95
94
|
s.interpret val
|
96
95
|
s
|
97
96
|
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
def interpret_sort_hash val
|
101
|
+
val = val.symbolize_keys
|
102
|
+
item = val.delete(:item) || "left"
|
103
|
+
sort_field = val[:return] || "db_content"
|
104
|
+
yield val, item, sort_field
|
105
|
+
end
|
98
106
|
end
|
99
107
|
end
|
100
108
|
end
|
@@ -10,17 +10,20 @@ class Card
|
|
10
10
|
def ensure_set &block
|
11
11
|
set_module = yield
|
12
12
|
set_module = card_set_module_const_get(set_module) unless set_module.is_a?(Module)
|
13
|
-
|
14
|
-
|
15
|
-
if e.message =~ /uninitialized constant (?:Card::Set::)?(.+)$/
|
16
|
-
define_set Regexp.last_match(1)
|
17
|
-
end
|
13
|
+
rescue NameError => error
|
14
|
+
define_set_from_error error
|
18
15
|
# try again - there might be another submodule that doesn't exist
|
19
16
|
ensure_set(&block)
|
20
17
|
else
|
21
18
|
set_module.extend Card::Set
|
22
19
|
end
|
23
20
|
|
21
|
+
def define_set_from_error error
|
22
|
+
match = error.message.match(/uninitialized constant (?:Card::Set::)?(.+)$/)
|
23
|
+
return unless match
|
24
|
+
define_set match[1]
|
25
|
+
end
|
26
|
+
|
24
27
|
def attachment name, args
|
25
28
|
include_set Abstract::Attachment
|
26
29
|
add_attributes name, "remote_#{name}_url".to_sym,
|
@@ -23,13 +23,21 @@ class Card
|
|
23
23
|
if condition == :when
|
24
24
|
validate_when_value val
|
25
25
|
else
|
26
|
-
|
27
|
-
|
26
|
+
validate_standard_condition_value condition, val
|
27
|
+
end
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
30
|
+
def validate_standard_condition_value condition, val
|
31
|
+
invalid = invalid_condition_values condition, val
|
32
|
+
return if invalid.empty?
|
33
|
+
|
34
|
+
raise ArgumentError,
|
35
|
+
"invalid option#{'s' if invalid.size > 1} '#{invalid}' "\
|
31
36
|
"for condition '#{condition}' in event '#{@event}'"
|
32
|
-
|
37
|
+
end
|
38
|
+
|
39
|
+
def invalid_condition_values condition, val
|
40
|
+
Array.wrap(val) - Api::OPTIONS[condition]
|
33
41
|
end
|
34
42
|
|
35
43
|
def validate_when_value val
|
data/lib/card/set/format.rb
CHANGED
@@ -106,20 +106,27 @@ class Card
|
|
106
106
|
|
107
107
|
def register_set_format format_class, mod
|
108
108
|
if all_set?
|
109
|
-
|
109
|
+
register_all_set_format format_class, mod
|
110
110
|
else
|
111
|
-
|
112
|
-
# ready to include dynamically in set members' format singletons
|
113
|
-
format_hash = modules[format_type][format_class] ||= {}
|
114
|
-
format_hash[shortname] ||= []
|
115
|
-
format_hash[shortname] << mod
|
111
|
+
register_standard_set_format format_class, mod
|
116
112
|
end
|
117
113
|
end
|
118
114
|
|
119
115
|
# make mod ready to include in base (non-set-specific) format classes
|
120
|
-
def
|
121
|
-
modules[:base_format]
|
122
|
-
|
116
|
+
def register_all_set_format format_class, mod
|
117
|
+
add_to_array_val modules[:base_format], format_class, mod
|
118
|
+
end
|
119
|
+
|
120
|
+
def register_standard_set_format format_class, mod
|
121
|
+
format_type = abstract_set? ? :abstract_format : :nonbase_format
|
122
|
+
# ready to include dynamically in set members' format singletons
|
123
|
+
format_hash = modules[format_type][format_class] ||= {}
|
124
|
+
add_to_array_val format_hash, shortname, mod
|
125
|
+
end
|
126
|
+
|
127
|
+
def add_to_array_val hash, key, val
|
128
|
+
hash[key] ||= []
|
129
|
+
hash[key] << val
|
123
130
|
end
|
124
131
|
|
125
132
|
class << self
|
data/lib/card/set/trait.rb
CHANGED
@@ -28,7 +28,7 @@ class Card
|
|
28
28
|
|
29
29
|
def add_attributes *args
|
30
30
|
Card.set_specific_attributes ||= []
|
31
|
-
Card.set_specific_attributes += args.map(&:
|
31
|
+
Card.set_specific_attributes += args.map(&:to_sym)
|
32
32
|
Card.set_specific_attributes.uniq!
|
33
33
|
end
|
34
34
|
|
@@ -37,14 +37,11 @@ class Card
|
|
37
37
|
Card::Set.traits[mod] || Card::Set.traits[mod] = {}
|
38
38
|
end
|
39
39
|
|
40
|
-
def add_traits
|
41
|
-
|
42
|
-
|
40
|
+
def add_traits traits, options
|
41
|
+
mod_traits = get_traits self
|
42
|
+
new_opts = new_trait_opts options
|
43
43
|
|
44
|
-
|
45
|
-
new_opts[:default_content] = options[:default] if options[:default]
|
46
|
-
|
47
|
-
args.each do |trait|
|
44
|
+
traits.each do |trait|
|
48
45
|
define_trait_card trait, new_opts
|
49
46
|
define_trait_reader trait if options[:reader]
|
50
47
|
define_trait_writer trait if options[:writer]
|
@@ -53,6 +50,12 @@ class Card
|
|
53
50
|
end
|
54
51
|
end
|
55
52
|
|
53
|
+
def new_trait_opts options
|
54
|
+
%i[type default_content].each_with_object({}).each do |key, hash|
|
55
|
+
hash[key] = options[key] if options[key]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
56
59
|
def define_trait_card trait, opts
|
57
60
|
define_method "#{trait}_card" do
|
58
61
|
fetch trait.to_sym, new: opts.clone, eager_cache: true
|
data/lib/card/subcards/add.rb
CHANGED
@@ -14,6 +14,8 @@ class Card
|
|
14
14
|
# add 'spoiler', content: 'John Snow is a Targaryen'
|
15
15
|
# add card_obj, delayed: true
|
16
16
|
|
17
|
+
include Args
|
18
|
+
|
17
19
|
def << value
|
18
20
|
add value
|
19
21
|
end
|
@@ -61,7 +63,7 @@ class Card
|
|
61
63
|
end
|
62
64
|
|
63
65
|
def new_by_attributes name, attributes={}
|
64
|
-
attributes
|
66
|
+
attributes = attributes&.symbolize_keys || {}
|
65
67
|
absolute_name = absolutize_subcard_name name
|
66
68
|
subcard_args = extract_subcard_args! attributes
|
67
69
|
card = initialize_by_attributes absolute_name, attributes
|
@@ -75,31 +77,8 @@ class Card
|
|
75
77
|
Card.assign_or_newish name, attributes, local_only: true
|
76
78
|
end
|
77
79
|
|
78
|
-
# TODO: this method already exists as card instance method in
|
79
|
-
# tracked_attributes.rb. Find a place for it where its accessible
|
80
|
-
# for both. There is one important difference. The keys are symbols
|
81
|
-
# here instead of strings
|
82
|
-
def extract_subcard_args! args
|
83
|
-
subcards = args.delete(:subcards) || {}
|
84
|
-
if (subfields = args.delete(:subfields))
|
85
|
-
subfields.each_pair do |key, value|
|
86
|
-
subcards[normalize_subfield_key(key)] = value
|
87
|
-
end
|
88
|
-
end
|
89
|
-
args.keys.each do |key|
|
90
|
-
subcards[key] = args.delete(key) if key =~ /^\+/
|
91
|
-
end
|
92
|
-
subcards
|
93
|
-
end
|
94
|
-
|
95
80
|
private
|
96
81
|
|
97
|
-
# ensure a leading '+'
|
98
|
-
def normalize_subfield_key key
|
99
|
-
key = Card::Codename.name(key) if key.is_a?(Symbol) && Card::Codename.exist?(key)
|
100
|
-
key.to_name.prepend_joint
|
101
|
-
end
|
102
|
-
|
103
82
|
# Handles hash with several subcards
|
104
83
|
def multi_add args
|
105
84
|
args.each_pair do |key, val|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
class Card
|
2
|
+
class Subcards
|
3
|
+
# Handling shared subcard args processing
|
4
|
+
module Args
|
5
|
+
def extract_subcard_args! args
|
6
|
+
safe_subcard_args args do |subcards|
|
7
|
+
extract_explicit_subfields subcards, args
|
8
|
+
extract_implicit_subfields subcards, args
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
# FIXME: the following should be handled before it gets this far
|
15
|
+
def safe_subcard_args args
|
16
|
+
subcards = args.delete(:subcards) || {}
|
17
|
+
yield subcards
|
18
|
+
subcards.try(:to_unsafe_h) || subcards
|
19
|
+
end
|
20
|
+
|
21
|
+
def extract_explicit_subfields subcards, args
|
22
|
+
return unless (subfields = args.delete :subfields)
|
23
|
+
|
24
|
+
subfields.each_pair do |key, value|
|
25
|
+
subcards[normalize_subfield_key(key)] = value
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# ensure a leading '+'
|
30
|
+
def normalize_subfield_key key
|
31
|
+
key = Card::Codename.name(key) if key.is_a?(Symbol) && Card::Codename.exist?(key)
|
32
|
+
key.to_name.prepend_joint
|
33
|
+
end
|
34
|
+
|
35
|
+
def extract_implicit_subfields subcards, args
|
36
|
+
args.each_key do |key|
|
37
|
+
subcards[key.to_s] = args.delete(key) if key.to_s.match?(/^\+/)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -14,17 +14,22 @@ class Card
|
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
def log_file_action path
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
17
|
+
def log_file_action path, &block
|
18
|
+
if File.exist?(path) && !@force
|
19
|
+
log_file_exists path
|
20
|
+
else
|
21
|
+
execute_and_log_file_action path, &block
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute_and_log_file_action path
|
26
|
+
status = File.exist?(path) ? "overridden" : "created"
|
27
|
+
yield
|
28
|
+
color_puts status, :green, path
|
29
|
+
end
|
26
30
|
|
27
|
-
|
31
|
+
def log_file_exists path
|
32
|
+
color_puts "file exists (use 'force=true' to override)", :yellow, path
|
28
33
|
end
|
29
34
|
|
30
35
|
# insert content into a file at a given line number
|
data/lib/card/view/options.rb
CHANGED
@@ -30,7 +30,8 @@ class Card
|
|
30
30
|
:nest_syntax, # full nest syntax
|
31
31
|
:wrap, # wrap the nest with a wrapper
|
32
32
|
:show, # render these views when optional
|
33
|
-
:hide
|
33
|
+
:hide, # do not render these views when optional
|
34
|
+
:unknown # view to use if nested card is unknown
|
34
35
|
], # show/hide can be view (Symbol), list of views (Array),
|
35
36
|
# or comma separated views (String)
|
36
37
|
# NOTE: although show and hide are in this non-inheriting group, they are
|
data/lib/card/view/permission.rb
CHANGED
@@ -28,11 +28,22 @@ class Card
|
|
28
28
|
format.view_setting setting_name, view
|
29
29
|
end
|
30
30
|
|
31
|
-
#
|
32
|
-
#
|
31
|
+
# views for unknown cards can be configured in view definitions
|
32
|
+
# or render/nest options (the latter take precedence)
|
33
33
|
def alter_unknown
|
34
|
+
return if card.known?
|
35
|
+
|
36
|
+
unknown_from_options || unknown_from_view_definition
|
37
|
+
end
|
38
|
+
|
39
|
+
def unknown_from_options
|
40
|
+
unknown.to_sym if unknown.present?
|
41
|
+
end
|
42
|
+
|
43
|
+
def unknown_from_view_definition
|
34
44
|
setting = setting(:unknown)
|
35
|
-
return if setting == true
|
45
|
+
return if setting == true # use original view
|
46
|
+
|
36
47
|
setting.is_a?(Symbol) ? setting : format.view_for_unknown(requested_view)
|
37
48
|
end
|
38
49
|
|
data/lib/cardio.rb
CHANGED
@@ -39,70 +39,17 @@ module Cardio
|
|
39
39
|
@cache ||= ::Rails.cache
|
40
40
|
end
|
41
41
|
|
42
|
+
# TODO: many of these defaults should be in mods!
|
42
43
|
def default_configs
|
43
|
-
|
44
|
-
read_only:
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
delaying: nil,
|
50
|
-
|
51
|
-
recaptcha_public_key: nil, # deprecated; use recaptcha_site_key instead
|
52
|
-
recaptcha_private_key: nil, # deprecated; use recaptcha_secret_key instead
|
53
|
-
recaptcha_proxy: nil,
|
54
|
-
recaptcha_site_key: nil,
|
55
|
-
recaptcha_secret_key: nil,
|
56
|
-
recaptcha_minimum_score: 0.5,
|
57
|
-
|
58
|
-
google_analytics_key: nil,
|
59
|
-
|
60
|
-
override_host: nil,
|
61
|
-
override_protocol: nil,
|
62
|
-
|
63
|
-
no_authentication: false,
|
64
|
-
files_web_path: "files",
|
65
|
-
|
66
|
-
max_char_count: 200,
|
67
|
-
max_depth: 20,
|
68
|
-
email_defaults: nil,
|
69
|
-
|
70
|
-
token_expiry: 2.days,
|
71
|
-
acts_per_page: 10,
|
72
|
-
space_last_in_multispace: true,
|
73
|
-
closed_search_limit: 10,
|
74
|
-
paging_limit: 20,
|
75
|
-
|
76
|
-
non_createable_types: [%w[signup setting set session bootswatch_skin customized_bootswatch_skin]], # FIXME
|
77
|
-
view_cache: false,
|
78
|
-
rss_enabled: false,
|
79
|
-
double_click: :signed_in,
|
80
|
-
|
81
|
-
encoding: "utf-8",
|
82
|
-
request_logger: false,
|
83
|
-
performance_logger: false,
|
84
|
-
sql_comments: true,
|
85
|
-
|
86
|
-
file_storage: :local,
|
87
|
-
file_buckets: {},
|
88
|
-
file_default_bucket: nil,
|
89
|
-
protocol_and_host: nil,
|
90
|
-
|
91
|
-
rich_text_editor: :tinymce,
|
92
|
-
|
93
|
-
persistent_cache: true,
|
94
|
-
prepopulate_cache: false,
|
95
|
-
machine_refresh: :cautious, # options: eager, cautious, never
|
96
|
-
compress_javascript: true,
|
97
|
-
|
98
|
-
allow_irreversible_admin_tasks: false,
|
99
|
-
raise_all_rendering_errors: false,
|
100
|
-
rescue_all_in_controller: true,
|
101
|
-
navbox_match_start_only: true,
|
44
|
+
defaults_from_yaml.merge(
|
45
|
+
read_only: !ENV["DECKO_READ_ONLY"].nil?,
|
46
|
+
load_strategy: (ENV["REPO_TMPSETS"] || ENV["TMPSETS"] ? :tmp_files : :eval)
|
47
|
+
)
|
48
|
+
end
|
102
49
|
|
103
|
-
|
104
|
-
|
105
|
-
|
50
|
+
def defaults_from_yaml
|
51
|
+
filename = File.expand_path "cardio/defaults.yml", __dir__
|
52
|
+
YAML.load_file filename
|
106
53
|
end
|
107
54
|
|
108
55
|
def set_config config
|
@@ -136,10 +83,6 @@ module Cardio
|
|
136
83
|
config.watchable_dirs["#{mod_path}/set"] = [:rb]
|
137
84
|
end
|
138
85
|
|
139
|
-
def read_only?
|
140
|
-
!ENV["DECKO_READ_ONLY"].nil?
|
141
|
-
end
|
142
|
-
|
143
86
|
# In production mode set_config gets called twice.
|
144
87
|
# The second call overrides all deck config settings
|
145
88
|
# so don't change settings here if they already exist
|