card 1.93.13 → 1.94.0

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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/config/initializers/01_core_extensions/persistent_identifiers.rb +8 -0
  4. data/config/locales/de.yml +1 -0
  5. data/config/locales/en.yml +1 -0
  6. data/lib/card.rb +2 -1
  7. data/lib/card/cache.rb +1 -1
  8. data/lib/card/content/clean.rb +6 -4
  9. data/lib/card/format/error.rb +1 -1
  10. data/lib/card/format/render.rb +1 -1
  11. data/lib/card/mod.rb +6 -1
  12. data/lib/card/mod/loader.rb +2 -0
  13. data/lib/card/name.rb +25 -5
  14. data/lib/card/query/attributes.rb +13 -8
  15. data/lib/card/set/event.rb +1 -1
  16. data/lib/card/tasks/card.rake +12 -0
  17. data/lib/card/tasks/card/migrate.rake +2 -0
  18. data/lib/card/view/options.rb +2 -1
  19. data/lib/cardio.rb +6 -6
  20. data/lib/cardio/utils.rb +30 -0
  21. data/mod/account/set/self/signin.rb +3 -13
  22. data/mod/account/set/type/signup.rb +1 -1
  23. data/mod/account/spec/set/self/signin_spec.rb +1 -1
  24. data/mod/basic_formats/set/all/base.rb +11 -3
  25. data/mod/basic_formats/set/all/json.rb +1 -0
  26. data/mod/basic_formats/set/self/head.rb +2 -3
  27. data/mod/bootstrap/db/migrate_core_cards/20170719163733_update_bootswatch_themes_to_4_beta.rb +2 -95
  28. data/mod/bootstrap/db/migrate_core_cards/lib/skin.rb +94 -0
  29. data/mod/bootstrap/script/update_skin_thumbnails.rb +9 -0
  30. data/mod/carrierwave/set/type/image.rb +1 -1
  31. data/mod/core/chunk/query_reference.rb +9 -2
  32. data/mod/core/set/all/event_conditions.rb +18 -8
  33. data/mod/core/set/all/fetch_helper.rb +11 -11
  34. data/mod/core/set/all/utils.rb +0 -12
  35. data/mod/core/spec/format/html_format_spec.rb +3 -3
  36. data/mod/core/spec/set/all/event_conditions_spec.rb +15 -0
  37. data/mod/core/spec/set/all/name_spec.rb +7 -0
  38. data/mod/core/spec/set/all/name_validations_spec.rb +0 -10
  39. data/mod/core/spec/set/all/rename_spec.rb +2 -2
  40. data/mod/pointer/set/abstract/02_pointer.rb +4 -0
  41. data/mod/search/set/abstract/00_filter_helper.rb +1 -1
  42. data/mod/search/set/abstract/02_search_params.rb +18 -0
  43. data/mod/search/set/abstract/search.rb +1 -1
  44. data/mod/search/set/self/navbox.rb +2 -2
  45. data/mod/search/set/self/search.rb +1 -19
  46. data/mod/search/spec/set/self/search_spec.rb +1 -1
  47. data/mod/standard/set/all/error.rb +6 -6
  48. data/mod/standard/set/all/rich_html/content.rb +2 -27
  49. data/mod/standard/set/all/rich_html/editing.rb +1 -1
  50. data/mod/standard/set/all/rich_html/title.rb +39 -0
  51. data/mod/standard/set/all/rich_html/toolbar.rb +1 -1
  52. data/mod/standard/set/type/cardtype.rb +8 -2
  53. data/mod/standard/spec/{chunk → content/chunk}/include_spec.rb +5 -5
  54. data/mod/standard/spec/{chunk → content/chunk}/link_spec.rb +1 -1
  55. data/mod/standard/spec/{chunk → content/chunk}/query_reference_spec.rb +0 -0
  56. metadata +11 -7
@@ -77,6 +77,7 @@ format :json do
77
77
  {
78
78
  id: card.id,
79
79
  name: card.name,
80
+ key: card.key,
80
81
  url: path
81
82
  }
82
83
  end
@@ -23,10 +23,9 @@ format :html do
23
23
  end
24
24
 
25
25
  def head_title
26
- title = root.card && root.card.name
27
- title = nil if title.blank?
26
+ title = root.safe_name
28
27
  title = params[:action] if title == "*placeholder"
29
- %(<title>#{title ? "#{title} - " : ''}#{Card.global_setting :title}</title>)
28
+ %(<title>#{title.present? ? "#{title} - " : ''}#{Card.global_setting :title}</title>)
30
29
  end
31
30
 
32
31
  def head_buttons
@@ -1,5 +1,7 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
+ require_relative "lib/skin"
4
+
3
5
  class UpdateBootswatchThemesTo4Beta < Card::Migration::Core
4
6
  def up
5
7
  remove_old_stuff
@@ -49,101 +51,6 @@ class UpdateBootswatchThemesTo4Beta < Card::Migration::Core
49
51
  Card["themeless bootstrap skin"].add_item! name.tr("_", " ")
50
52
  end
51
53
  end
52
-
53
- class Skin
54
- include ::Card::Model::SaveHelper
55
-
56
- class << self
57
- def vendor_path
58
- File.expand_path "../../../vendor", __FILE__
59
- end
60
-
61
- def bootstrap_scss_path filename
62
- File.join vendor_path, "bootstrap", "scss", "_#{filename}.scss"
63
- end
64
-
65
- def themes
66
- json = File.read File.join(vendor_path, "bootswatch", "docs", "api", "4.json")
67
- JSON.parse(json)["themes"].map { |theme| theme["name"] }
68
- end
69
- end
70
-
71
- def initialize theme_name
72
- @theme_name = theme_name.downcase
73
- @skin_name = "#{theme_name} skin"
74
- @skin_codename = @skin_name.downcase.tr(" ", "_")
75
- end
76
-
77
- def create_or_update
78
- Card.exists?(@skin_name) ? update_skin : create_skin
79
- end
80
-
81
- def create_skin
82
- Card.create! name: @skin_name,
83
- codename: @skin_codename,
84
- type_id: Card::SkinID,
85
- content: "[[themeless bootstrap skin]]\n[[+bootswatch theme]]",
86
- subcards: create_subcard_args
87
- end
88
-
89
- def update_skin
90
- update_css file_name: "bootstrap.css", field_name: "bootswatch theme"
91
- update_tumbnail
92
- end
93
-
94
- def update_scss file_name:, field_name: file_name
95
- update_card "#{@skin_name}+#{field_name}", style_args(file_name)
96
- end
97
-
98
- def update_css file_name:, field_name: file_name
99
- ensure_card "#{@skin_name}+#{field_name}", style_args(file_name, Card::CssID)
100
- end
101
-
102
- def update_tumbnail
103
- update_card "#{@skin_name}+Image", thumbnail_args
104
- end
105
-
106
- private
107
-
108
- def create_subcard_args
109
- {
110
- "+bootswatch theme" => style_args("bootstrap.css", Card::CssID),
111
- "+Image" => thumbnail_args
112
- }
113
- end
114
-
115
- def style_args file_name, type_id=Card::ScssID
116
- paths = Array.wrap(file_name).map { |fn| resource_path(fn) }
117
- content = paths.map { |p| File.read(p) }.join "\n"
118
- { type_id: type_id, content: content }
119
- end
120
-
121
- def thumbnail_args
122
- {
123
- codename: "#{@skin_codename}_image",
124
- type_id: Card::ImageID,
125
- mod: :bootstrap, storage_type: :coded,
126
- image: File.open(thumbnail_path)
127
- }
128
- end
129
-
130
- def resource_path resource
131
- resource = "_#{resource}.scss" unless resource.include? "."
132
- if resource.include? File::SEPARATOR
133
- resource
134
- else
135
- File.join base_resource_dir, resource
136
- end
137
- end
138
-
139
- def thumbnail_path
140
- File.join Skin.vendor_path, "bootswatch", "docs", @theme_name, "thumbnail.png"
141
- end
142
-
143
- def base_resource_dir
144
- File.join Skin.vendor_path, "bootswatch", "dist", @theme_name
145
- end
146
- end
147
54
  end
148
55
 
149
56
 
@@ -0,0 +1,94 @@
1
+ # Update or create a bootstrap skin
2
+ class Skin
3
+ include ::Card::Model::SaveHelper
4
+
5
+ class << self
6
+ def vendor_path
7
+ File.expand_path "../../../../vendor", __FILE__
8
+ end
9
+
10
+ def bootstrap_scss_path filename
11
+ File.join vendor_path, "bootstrap", "scss", "_#{filename}.scss"
12
+ end
13
+
14
+ def themes
15
+ json = File.read File.join(vendor_path, "bootswatch", "docs", "api", "4.json")
16
+ JSON.parse(json)["themes"].map { |theme| theme["name"] }
17
+ end
18
+ end
19
+
20
+ def initialize theme_name
21
+ @theme_name = theme_name.downcase
22
+ @skin_name = "#{theme_name} skin"
23
+ @skin_codename = @skin_name.downcase.tr(" ", "_")
24
+ end
25
+
26
+ def create_or_update
27
+ Card.exists?(@skin_name) ? update_skin : create_skin
28
+ end
29
+
30
+ def create_skin
31
+ Card.create! name: @skin_name,
32
+ codename: @skin_codename,
33
+ type_id: Card::SkinID,
34
+ content: "[[themeless bootstrap skin]]\n[[+bootswatch theme]]",
35
+ subcards: create_subcard_args
36
+ end
37
+
38
+ def update_skin
39
+ update_css file_name: "bootstrap.css", field_name: "bootswatch theme"
40
+ # don't update thumbnails since they are stored as coded files in the gem
41
+ # there's a script for doing that
42
+ # update_tumbnail
43
+ end
44
+
45
+ def update_scss file_name:, field_name: file_name
46
+ update_card "#{@skin_name}+#{field_name}", style_args(file_name)
47
+ end
48
+
49
+ def update_css file_name:, field_name: file_name
50
+ ensure_card "#{@skin_name}+#{field_name}", style_args(file_name, Card::CssID)
51
+ end
52
+
53
+ def update_thumbnail
54
+ update_card "#{@skin_name}+Image", thumbnail_args
55
+ end
56
+
57
+ private
58
+
59
+ def create_subcard_args
60
+ { "+bootswatch theme" => style_args("bootstrap.css", Card::CssID) }
61
+ end
62
+
63
+ def style_args file_name, type_id=Card::ScssID
64
+ paths = Array.wrap(file_name).map { |fn| resource_path(fn) }
65
+ content = paths.map { |p| File.read(p) }.join "\n"
66
+ { type_id: type_id, content: content }
67
+ end
68
+
69
+ def thumbnail_args
70
+ {
71
+ codename: "#{@skin_codename}_image",
72
+ type_id: Card::ImageID,
73
+ mod: :bootstrap, storage_type: :coded,
74
+ image: File.open(thumbnail_path)
75
+ }
76
+ end
77
+
78
+ def resource_path resource
79
+ resource = "_#{resource}.scss" unless resource.include? "."
80
+ if resource.include? File::SEPARATOR
81
+ resource
82
+ else
83
+ File.join base_resource_dir, resource
84
+ end
85
+ end
86
+
87
+ def thumbnail_path
88
+ File.join Skin.vendor_path, "bootswatch", "docs", @theme_name, "thumbnail.png"
89
+ end
90
+
91
+ def base_resource_dir
92
+ File.join Skin.vendor_path, "bootswatch", "dist", @theme_name
93
+ end
94
+ end
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ require_relative "../db/migrate_core_cards/lib/skin"
4
+
5
+ puts "Updating bootstrap themes ..."
6
+ Skin.themes.each do |theme_name|
7
+ puts theme_name
8
+ Skin.new(theme_name).update_thumbnail
9
+ end
@@ -63,7 +63,7 @@ format :html do
63
63
  if source.blank? || source == "missing"
64
64
  # FIXME - these images should be "broken", not "missing"
65
65
  # ("missing" is the view for "unknown" now, so we shouldn't further confuse things)
66
- "<!-- image missing #{@card.name} -->"
66
+ "<!-- image missing #{safe_name} -->"
67
67
  else
68
68
  image_tag source
69
69
  end
@@ -23,7 +23,7 @@ module Card::Content::Chunk
23
23
  Card::Query::ATTRIBUTES.keys +
24
24
  Card::Query::CONJUNCTIONS.keys +
25
25
  %w[desc asc count]
26
- ).map(&:to_name)
26
+ ).map(&:to_s)
27
27
  )
28
28
 
29
29
  Card::Content::Chunk.register_class(
@@ -53,10 +53,17 @@ module Card::Content::Chunk
53
53
 
54
54
  class << self
55
55
  def full_match content, prefix
56
+ # matches cardnames that are not keywords
57
+ # FIXME: would not match cardnames that are keywords
56
58
  match, offset = super(content, prefix)
57
- return unless match && !QUERY_KEYWORDS.include?(match[1].to_name)
59
+ return if !match || keyword?(match[1])
58
60
  [match, offset]
59
61
  end
62
+
63
+ def keyword? str
64
+ return unless str
65
+ QUERY_KEYWORDS.include?(str.tr(" ", "_").downcase)
66
+ end
60
67
  end
61
68
 
62
69
  def interpret match, _content
@@ -1,30 +1,30 @@
1
- EVENT_CONDITIONS = %i[set on changed when].freeze
1
+ EVENT_CONDITIONS = %i[set on changed when optional].freeze
2
2
 
3
- def event_applies? opts
3
+ def event_applies? event, opts
4
4
  EVENT_CONDITIONS.all? do |key|
5
- send "#{key}_condition_applies?", opts[key]
5
+ send "#{key}_condition_applies?", event, opts[key]
6
6
  end
7
7
  end
8
8
 
9
9
  private
10
10
 
11
- def set_condition_applies? set_module
11
+ def set_condition_applies? _event, set_module
12
12
  singleton_class.include?(set_module)
13
13
  end
14
14
 
15
- def on_condition_applies? actions
15
+ def on_condition_applies? _event, actions
16
16
  actions = Array(actions).compact
17
17
  return true if actions.empty?
18
18
  actions.include? @action
19
19
  end
20
20
 
21
- def changed_condition_applies? db_columns
21
+ def changed_condition_applies? _event, db_columns
22
22
  db_columns = Array(db_columns).compact
23
23
  return true if db_columns.empty?
24
24
  db_columns.any? { |col| single_changed_condition_applies? col }
25
25
  end
26
26
 
27
- def when_condition_applies? block
27
+ def when_condition_applies? _event, block
28
28
  case block
29
29
  when Proc then block.call(self)
30
30
  when Symbol then send block
@@ -32,6 +32,11 @@ def when_condition_applies? block
32
32
  end
33
33
  end
34
34
 
35
+ def optional_condition_applies? event, optional
36
+ return true unless optional
37
+ skip_event? event
38
+ end
39
+
35
40
  def single_changed_condition_applies? db_column
36
41
  return true unless db_column
37
42
  db_column =
@@ -53,6 +58,11 @@ def wrong_stage opts
53
58
  end
54
59
 
55
60
  def wrong_action action
56
- return false if on_condition_applies? action
61
+ return false if on_condition_applies?(nil, action)
57
62
  "on: #{action} method #{method} called on #{@action}"
58
63
  end
64
+
65
+ def skip_event? event
66
+ @names_of_skipped_events ||= ::Set.new(Array.wrap(skip_event).map(&:to_sym))
67
+ !@names_of_skipped_events.include? event
68
+ end
@@ -13,6 +13,16 @@ module ClassMethods
13
13
  end
14
14
  end
15
15
 
16
+ def safe_param param
17
+ if param.respond_to? :to_unsafe_h
18
+ # clone doesn't work for Parameters
19
+ param.to_unsafe_h
20
+ else
21
+ # clone so that original params remain unaltered. need deeper clone?
22
+ (param || {}).clone
23
+ end
24
+ end
25
+
16
26
  private
17
27
 
18
28
  def standard_controller_fetch args, card_opts
@@ -23,23 +33,13 @@ module ClassMethods
23
33
  end
24
34
 
25
35
  def controller_fetch_opts args
26
- opts = safe_card_opts args[:card]
36
+ opts = safe_param args[:card]
27
37
  opts[:type] ||= args[:type] if args[:type]
28
38
  # for /new/:type shortcut. we should handle in routing and deprecate this
29
39
  opts[:name] ||= Card::Name.url_key_to_standard(args[:id])
30
40
  opts
31
41
  end
32
42
 
33
- def safe_card_opts card_opts
34
- if card_opts.respond_to? :to_unsafe_h
35
- # clone doesn't work for Parameters
36
- card_opts.to_unsafe_h
37
- else
38
- # clone so that original params remain unaltered. need deeper clone?
39
- (card_opts || {}).clone
40
- end
41
- end
42
-
43
43
  def validate_fetch_opts! opts
44
44
  return unless opts[:new] && opts[:skip_virtual]
45
45
  raise Card::Error, "fetch called with new args and skip_virtual"
@@ -1,12 +1,4 @@
1
1
  module ClassMethods
2
- def delete_tmp_files id=nil
3
- dir = Cardio.paths["files"].existent.first + "/tmp"
4
- dir += "/#{id}" if id
5
- FileUtils.rm_rf dir, secure: true
6
- rescue
7
- Rails.logger.info "failed to remove tmp files"
8
- end
9
-
10
2
  def merge_list attribs, opts={}
11
3
  unmerged = []
12
4
  attribs.each do |row|
@@ -49,8 +41,4 @@ module ClassMethods
49
41
  card.update_attributes! attribs
50
42
  end
51
43
  end
52
-
53
- def seed_test_db
54
- system "env RAILS_ENV=test bundle exec rake db:fixtures:load"
55
- end
56
44
  end
@@ -32,10 +32,10 @@ RSpec.describe Card::Format::HtmlFormat do
32
32
 
33
33
  it "renders top menu" do
34
34
  is_expected.to have_tag "header" do
35
- with_tag 'a.nav-link.internal-link[href="/"]', text: "Home"
36
- with_tag 'a.nav-link.internal-link[href="/:recent"]', text: "Recent"
35
+ with_tag 'a.nav-link.internal-link[href=""]', text: "Home"
36
+ with_tag 'a.nav-link.internal-link[href=":recent"]', text: "Recent"
37
37
  with_tag 'form.navbox-form[action="/*search"]' do
38
- with_tag 'input[name="_keyword"]'
38
+ with_tag 'input[name="query[keyword]"]'
39
39
  end
40
40
  end
41
41
  end
@@ -50,5 +50,20 @@ describe Card::Set::All::EventConditions, "event" do
50
50
  expect(@log).to contain_exactly(*content_before_change)
51
51
  end
52
52
  end
53
+
54
+ specify "skip event condition" do
55
+ with_test_events do
56
+ test_event :validate, on: :update, optional: true, for: "A" do
57
+ add_to_log "not skipped"
58
+ end
59
+ Card["A"].update_attributes! content: "changed content", skip_event: :test_event_0
60
+
61
+ aggregate_failures do
62
+ expect(@log).to be_empty
63
+ Card["A"].update_attributes! content: "changed content"
64
+ expect(@log).to contain_exactly "not skipped"
65
+ end
66
+ end
67
+ end
53
68
  end
54
69
  end
@@ -57,6 +57,13 @@ describe Card::Set::All::Name do
57
57
  end
58
58
  end
59
59
 
60
+ describe "event: escape_name" do
61
+ it "escapes invalid characters" do
62
+ c = Card.create! name: "8 / 5 <script>"
63
+ expect(c.name).to eq("8 &#47; 5 &#60;script&#62;")
64
+ end
65
+ end
66
+
60
67
  describe "codename" do
61
68
  before do
62
69
  @card = Card["a"]