card 1.92 → 1.92.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/initializers/02_patches/active_job.rb +59 -11
- data/lib/card/act_manager/stage_director.rb +1 -1
- data/lib/card/act_manager/stage_director/phases.rb +1 -0
- data/lib/card/cache.rb +1 -1
- data/lib/card/format/render.rb +1 -1
- data/lib/card/mod/load_strategy.rb +6 -7
- data/mod/account/set/right/account.rb +2 -2
- data/mod/account/set/type/signup.rb +5 -5
- data/mod/bootstrap/lib/bootstrap/component/carousel.rb +4 -4
- data/mod/bootstrap/lib/bootstrap/component/form.rb +2 -2
- data/mod/bootstrap/spec/set/all/bootstrap/carousel_spec.rb +9 -0
- data/mod/carrierwave/set/abstract/attachment/upload_cache.rb +0 -1
- data/mod/carrierwave/set/type/file.rb +1 -5
- data/mod/core/format/html_format.rb +1 -2
- data/mod/core/set/all/cache.rb +5 -4
- data/mod/core/set/all/collection.rb +2 -2
- data/mod/history/lib/card/act/act_renderer.rb +12 -11
- data/mod/history/set/all/history.rb +11 -7
- data/mod/machines/file/all_style_machine_output/file.css +24 -0
- data/mod/notifications/set/all/send_notifications.rb +7 -8
- data/mod/notifications/set/right/followers.rb +28 -23
- data/mod/pointer/set/abstract/02_pointer/edit.rb +4 -3
- data/mod/standard/set/all/rich_html/content.rb +1 -1
- data/mod/standard/set/all/rich_html/form.rb +5 -1
- data/mod/standard/set/all/rich_html/wrapper.rb +4 -3
- data/spec/lib/card/set/event_spec.rb +22 -0
- data/spec/support/matchers/card_matchers.rb +39 -13
- data/spec/support/matchers/html_matchers.rb +29 -0
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f28f43edfef2752d5cfefbfed009278c4852af46
|
4
|
+
data.tar.gz: 4f94927063af307286622bf14c9c21738720c3fd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 685d0d0cf2e26a2237ac3d0869321e5dcfa403fd7063599e6b458fa971e7279cf05b40c91370ef4c34717fa41a7f1256f7cb5f93cdf70a286a3e82d3363aa4b1
|
7
|
+
data.tar.gz: 211059237c2230c26de7e3e2e53bf06d68af128d7b7dd66efd3cacb926510fcd1cddf9da70e34d094eec4fa253bf5b112a341dd0b926bb50d24bbef7d4a42b82
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2
|
1
|
+
0.2.1
|
@@ -1,33 +1,81 @@
|
|
1
1
|
module Patches
|
2
2
|
module ActiveJob
|
3
|
-
#
|
3
|
+
# Monkeypatch ActiveJob so that it can handle more types of arguments.
|
4
|
+
# Add Integer hash keys and Symbol, Time, DateTime hash values and
|
5
|
+
# ActionController::Parameters
|
4
6
|
module Arguments
|
5
7
|
CLASS_NAME_KEY = "_aj_class_name_key".freeze
|
8
|
+
VALUE_KEY = "_aj_value_key".freeze
|
9
|
+
INTEGER_KEYS_KEY = "_aj_integer_keys".freeze
|
6
10
|
|
7
11
|
private
|
8
12
|
|
9
13
|
def serialize_argument argument
|
10
14
|
case argument
|
11
15
|
when Symbol, Time, DateTime
|
12
|
-
{
|
16
|
+
{ VALUE_KEY => argument.to_s, CLASS_NAME_KEY => argument.class.to_s }
|
13
17
|
when ActionController::Parameters
|
14
|
-
{
|
15
|
-
CLASS_NAME_KEY
|
18
|
+
{ VALUE_KEY => serialize_argument(argument.to_unsafe_h),
|
19
|
+
CLASS_NAME_KEY => argument.class.to_s }
|
20
|
+
when Hash
|
21
|
+
integer_keys = argument.each_key.grep(Integer).map(&:to_s)
|
22
|
+
result = super
|
23
|
+
result[INTEGER_KEYS_KEY] = integer_keys
|
24
|
+
result
|
16
25
|
else
|
17
26
|
super
|
18
27
|
end
|
19
28
|
end
|
20
29
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
30
|
+
def serialize_hash_key key
|
31
|
+
case key
|
32
|
+
when Integer
|
33
|
+
key.to_s
|
34
|
+
else
|
35
|
+
super
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# all custom serialized arguments become hashes
|
40
|
+
# hence for deserializing we only have to check hashes
|
41
|
+
def deserialize_hash serialized_hash
|
42
|
+
if serialized_hash[CLASS_NAME_KEY]
|
43
|
+
deserialize_object serialized_hash
|
44
|
+
else
|
45
|
+
handle_integer_keys super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def handle_integer_keys result
|
50
|
+
if (integer_keys = result.delete(INTEGER_KEYS_KEY) && integer_keys.present?)
|
51
|
+
result = transform_integer_keys(result, integer_keys)
|
52
|
+
end
|
53
|
+
result
|
54
|
+
end
|
55
|
+
|
56
|
+
def deserialize_object hash
|
57
|
+
value = hash[VALUE_KEY]
|
58
|
+
class_name = hash[CLASS_NAME_KEY]
|
59
|
+
case class_name
|
25
60
|
when "Symbol"
|
26
|
-
|
61
|
+
value.to_sym
|
27
62
|
when "Time", "DateTime"
|
28
|
-
Object.const_get(
|
63
|
+
Object.const_get(class_name).parse value
|
64
|
+
when "ActionController::Parameters"
|
65
|
+
# TODO: handle the permitted status
|
66
|
+
ActionController::Parameters.new deserialize_hash(value)
|
29
67
|
else
|
30
|
-
|
68
|
+
value
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def transform_integer_keys(hash, integer_keys)
|
73
|
+
hash.transform_keys do |key|
|
74
|
+
if integer_keys.include?(key)
|
75
|
+
key.to_i
|
76
|
+
else
|
77
|
+
key
|
78
|
+
end
|
31
79
|
end
|
32
80
|
end
|
33
81
|
end
|
data/lib/card/cache.rb
CHANGED
@@ -44,7 +44,7 @@ class Card
|
|
44
44
|
extend Card::Cache::Prepopulate
|
45
45
|
|
46
46
|
@prepopulating = %w(test cucumber).include? Rails.env
|
47
|
-
@no_rails_cache = %w(test
|
47
|
+
@no_rails_cache = %w(test).include?(Rails.env) ||
|
48
48
|
ENV["NO_RAILS_CACHE"]
|
49
49
|
@@cache_by_class = {}
|
50
50
|
cattr_reader :cache_by_class
|
data/lib/card/format/render.rb
CHANGED
@@ -87,7 +87,7 @@ class Card
|
|
87
87
|
def prepare_stub_nest stub_hash
|
88
88
|
stub_card = Card.fetch_from_cast stub_hash[:cast]
|
89
89
|
stub_options = stub_hash[:options]
|
90
|
-
if stub_card
|
90
|
+
if stub_card&.key.present? && stub_card.key == card.key
|
91
91
|
stub_options[:nest_name] ||= "_self"
|
92
92
|
end
|
93
93
|
yield stub_card, stub_hash[:mode], stub_options, stub_hash[:override]
|
@@ -1,14 +1,13 @@
|
|
1
|
-
require_relative "load_strategy/eval"
|
2
|
-
require_relative "load_strategy/pattern_tmp_files"
|
3
|
-
require_relative "load_strategy/set_binding_magic"
|
4
|
-
require_relative "load_strategy/set_tmp_files"
|
5
|
-
require_relative "load_strategy/tmp_files"
|
6
|
-
|
7
1
|
class Card
|
8
2
|
module Mod
|
3
|
+
require_dependency "card/mod/load_strategy/eval"
|
4
|
+
require_dependency "card/mod/load_strategy/pattern_tmp_files"
|
5
|
+
require_dependency "card/mod/load_strategy/set_binding_magic"
|
6
|
+
require_dependency "card/mod/load_strategy/set_tmp_files"
|
7
|
+
require_dependency "card/mod/load_strategy/tmp_files"
|
8
|
+
|
9
9
|
# Shared code for the three different load strategies: Eval, TmpFiles and BindingMagic
|
10
10
|
class LoadStrategy
|
11
|
-
|
12
11
|
def self.klass symbol
|
13
12
|
case symbol
|
14
13
|
when :tmp_files then TmpFiles
|
@@ -104,12 +104,12 @@ event :set_default_status, :prepare_to_validate, on: :create do
|
|
104
104
|
add_subfield :status, content: default_status
|
105
105
|
end
|
106
106
|
|
107
|
-
def
|
107
|
+
def can_approve?
|
108
108
|
Card.new(type_id: Card.default_accounted_type_id).ok? :create
|
109
109
|
end
|
110
110
|
|
111
111
|
event :generate_confirmation_token,
|
112
|
-
:prepare_to_store, on: :create, when: :
|
112
|
+
:prepare_to_store, on: :create, when: :can_approve? do
|
113
113
|
add_subfield :token, content: generate_token
|
114
114
|
end
|
115
115
|
|
@@ -2,7 +2,7 @@ format :html do
|
|
2
2
|
def invitation?
|
3
3
|
return @invitation unless @invitation.nil?
|
4
4
|
@invitation = Auth.signed_in? &&
|
5
|
-
(card.fetch trait: :account, new: {}).
|
5
|
+
(card.fetch trait: :account, new: {}).can_approve?
|
6
6
|
# consider making account a card_accessor?
|
7
7
|
end
|
8
8
|
|
@@ -87,13 +87,13 @@ format :html do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
def approve_with_token_link account, token_action
|
90
|
-
return unless account.
|
90
|
+
return unless account.can_approve?
|
91
91
|
link_to_card card, "#{token_action} verification email",
|
92
92
|
path: { action: :update, approve_with_token: true }
|
93
93
|
end
|
94
94
|
|
95
95
|
def approve_without_token_link account
|
96
|
-
return unless account.
|
96
|
+
return unless account.can_approve?
|
97
97
|
link_to_card card, "Approve without verification",
|
98
98
|
path: { action: :update, approve_without_token: true }
|
99
99
|
end
|
@@ -139,7 +139,7 @@ end
|
|
139
139
|
event :approve_with_token, :validate,
|
140
140
|
on: :update,
|
141
141
|
when: proc { Env.params[:approve_with_token] } do
|
142
|
-
abort :failure, "illegal approval" unless account.
|
142
|
+
abort :failure, "illegal approval" unless account.can_approve?
|
143
143
|
account.reset_token
|
144
144
|
account.send_account_verification_email
|
145
145
|
end
|
@@ -147,7 +147,7 @@ end
|
|
147
147
|
event :approve_without_token, :validate,
|
148
148
|
on: :update,
|
149
149
|
when: proc { Env.params[:approve_without_token] } do
|
150
|
-
abort :failure, "illegal approval" unless account.
|
150
|
+
abort :failure, "illegal approval" unless account.can_approve?
|
151
151
|
activate_account
|
152
152
|
end
|
153
153
|
|
@@ -11,7 +11,7 @@ class Bootstrap
|
|
11
11
|
@items = []
|
12
12
|
instance_exec &block
|
13
13
|
|
14
|
-
@html.div class: "carousel slide", id: id, data
|
14
|
+
@html.div class: "carousel slide", id: id, "data-ride" => "carousel" do
|
15
15
|
indicators
|
16
16
|
items
|
17
17
|
control_prev
|
@@ -30,7 +30,7 @@ class Bootstrap
|
|
30
30
|
add_class html_opts, "active" if index == @active_item_index
|
31
31
|
@html.div html_opts do
|
32
32
|
item = item.call if item.respond_to?(:call)
|
33
|
-
@html
|
33
|
+
@html << item if item.is_a?(String)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
@@ -38,7 +38,7 @@ class Bootstrap
|
|
38
38
|
|
39
39
|
def control_prev
|
40
40
|
@html.a class: "carousel-control-prev", href: "##{@id}", role: "button",
|
41
|
-
data
|
41
|
+
"data-slide" => "prev" do
|
42
42
|
@html.span class: "carousel-control-prev-icon", "aria-hidden" => "true"
|
43
43
|
@html.span "Previous", class: "sr-only"
|
44
44
|
end
|
@@ -46,7 +46,7 @@ class Bootstrap
|
|
46
46
|
|
47
47
|
def control_next
|
48
48
|
@html.a class: "carousel-control-next", href: "##{@id}", role: "button",
|
49
|
-
data
|
49
|
+
"data-slide": "next" do
|
50
50
|
@html.span class: "carousel-control-next-icon", "aria-hidden" => "true"
|
51
51
|
@html.span "Next", class: "sr-only"
|
52
52
|
end
|
@@ -40,7 +40,7 @@ class Bootstrap
|
|
40
40
|
def input type, text: nil, label: nil, id: nil
|
41
41
|
@html.input id: id, class: "form-control", type: type do
|
42
42
|
@html.label label, for: id if label
|
43
|
-
@html
|
43
|
+
@html << text if text
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
@@ -56,7 +56,7 @@ class Bootstrap
|
|
56
56
|
define_method tag do |text: nil, id:, label: |
|
57
57
|
@html.input id: id, class: "form-control", type: tag do
|
58
58
|
@html.label label, for: id if label
|
59
|
-
@html
|
59
|
+
@html << text
|
60
60
|
end
|
61
61
|
end
|
62
62
|
end
|
@@ -62,4 +62,13 @@ describe Bootstrap::Component::Carousel do
|
|
62
62
|
end
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
it "doesn't escape markup" do
|
67
|
+
carousel = subject.bs_carousel "csID", 0 do
|
68
|
+
item "<strong>item 2</strong>"
|
69
|
+
end
|
70
|
+
expect(carousel).to have_tag "div.carousel-item" do
|
71
|
+
with_tag :strong, text: "item 2"
|
72
|
+
end
|
73
|
+
end
|
65
74
|
end
|
@@ -8,7 +8,6 @@ end
|
|
8
8
|
event :upload_attachment, :prepare_to_validate,
|
9
9
|
on: :save, when: proc { |c| c.preliminary_upload? } do
|
10
10
|
save_original_filename # save original filename as comment in action
|
11
|
-
# binding.pry
|
12
11
|
write_identifier # set db_content
|
13
12
|
# (needs original filename to determine extension)
|
14
13
|
store_attachment!
|
@@ -107,11 +107,7 @@ format :html do
|
|
107
107
|
<table role="presentation" class="table table-striped">
|
108
108
|
<tbody class="files">
|
109
109
|
<tr class="template-download fade show">
|
110
|
-
<td>
|
111
|
-
<span class="preview">
|
112
|
-
#{preview}
|
113
|
-
</span>
|
114
|
-
</td>
|
110
|
+
<td><span class="preview">#{preview}</span></td>
|
115
111
|
<td>
|
116
112
|
<p class="name">
|
117
113
|
#{card.original_filename}
|
@@ -53,8 +53,7 @@ class Card
|
|
53
53
|
end
|
54
54
|
|
55
55
|
def layout_from_card_or_code name
|
56
|
-
layout_card = Card.
|
57
|
-
skip_modules: true
|
56
|
+
layout_card = Card.quick_fetch name
|
58
57
|
if layout_card && layout_card.ok?(:read)
|
59
58
|
layout_card.content
|
60
59
|
elsif (hardcoded_layout = LAYOUTS[name])
|
data/mod/core/set/all/cache.rb
CHANGED
@@ -54,6 +54,7 @@ def view_cache_keys new_key=nil
|
|
54
54
|
@view_cache_keys << new_key if new_key
|
55
55
|
append_missing_view_cache_keys
|
56
56
|
@view_cache_keys.uniq!
|
57
|
+
@view_cache_keys
|
57
58
|
end
|
58
59
|
|
59
60
|
def append_missing_view_cache_keys
|
@@ -63,15 +64,15 @@ def append_missing_view_cache_keys
|
|
63
64
|
end
|
64
65
|
|
65
66
|
def hard_write_view_cache_keys
|
66
|
-
#
|
67
|
+
# puts "WRITE VIEW CACHE KEYS (#{name}): #{view_cache_keys}"
|
67
68
|
return unless Card.cache.hard
|
68
|
-
Card.cache.hard.write_attribute key, :view_cache_keys,
|
69
|
+
Card.cache.hard.write_attribute key, :view_cache_keys, view_cache_keys
|
69
70
|
end
|
70
71
|
|
71
72
|
def expire_views
|
72
|
-
#
|
73
|
+
# puts "EXPIRE VIEW CACHE (#{name}): #{view_cache_keys}"
|
73
74
|
return unless view_cache_keys.present?
|
74
|
-
Array.wrap(
|
75
|
+
Array.wrap(view_cache_keys).each do |view_cache_key|
|
75
76
|
Card::View.cache.delete view_cache_key
|
76
77
|
end
|
77
78
|
@view_cache_keys = nil
|
@@ -35,7 +35,7 @@ class Card
|
|
35
35
|
row 10, 2 do
|
36
36
|
column do
|
37
37
|
html title
|
38
|
-
tag(:span, "text-muted pl-1 badge") {summary}
|
38
|
+
tag(:span, "text-muted pl-1 badge") { summary }
|
39
39
|
end
|
40
40
|
column act_links, class: "text-right"
|
41
41
|
end
|
@@ -93,7 +93,7 @@ class Card
|
|
93
93
|
def count_types
|
94
94
|
@count_types ||=
|
95
95
|
approved_actions.each_with_object(
|
96
|
-
Hash.new {|h, k| h[k] = 0}
|
96
|
+
Hash.new { |h, k| h[k] = 0 }
|
97
97
|
) do |action, type_cnt|
|
98
98
|
type_cnt[action.action_type] += 1
|
99
99
|
end
|
@@ -186,18 +186,19 @@ class Card
|
|
186
186
|
|
187
187
|
def revert_link
|
188
188
|
revert_actions_link "revert to this", revert_to: :this,
|
189
|
-
|
189
|
+
slot_selector: ".card-slot.history-view"
|
190
190
|
end
|
191
191
|
|
192
|
-
def revert_actions_link link_text, revert_to: :this, slot_selector:
|
192
|
+
def revert_actions_link link_text, revert_to: :this, slot_selector: nil, html_args: {}
|
193
193
|
return unless card.ok? :update
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
194
|
+
html_args.merge! remote: true, method: :post, rel: "nofollow",
|
195
|
+
path: { action: :update, view: :open, look_in_trash: true,
|
196
|
+
revert_actions: @act.actions.map(&:id),
|
197
|
+
revert_to: revert_to }
|
198
|
+
|
199
|
+
html_args[:path]["data-slot-selector"] = slot_selector if slot_selector
|
200
|
+
add_class html_args, "slotter"
|
201
|
+
link_to link_text, html_args
|
201
202
|
end
|
202
203
|
|
203
204
|
def deletion_act?
|
@@ -30,7 +30,7 @@ event :finalize_action, :finalize, when: :finalize_action? do
|
|
30
30
|
@current_action.update_attributes! card_id: id
|
31
31
|
|
32
32
|
# Note: #last_change_on uses the id to sort by date
|
33
|
-
# so the changes for the create changes have to be created
|
33
|
+
# so the changes for the create changes have to be created before the first change
|
34
34
|
store_card_changes_for_create_action if first_change?
|
35
35
|
store_card_changes if @current_action.action_type != :create
|
36
36
|
elsif @current_action.card_changes.reload.empty?
|
@@ -77,15 +77,19 @@ end
|
|
77
77
|
event :finalize_act,
|
78
78
|
after: :finalize_action,
|
79
79
|
when: proc { |c| c.act_card? } do
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
80
|
+
@current_act.update_attributes! card_id: id
|
81
|
+
end
|
82
|
+
|
83
|
+
event :remove_empty_act,
|
84
|
+
:integrate_with_delay_final,
|
85
|
+
when: proc { |c| c.act_card? } do
|
86
|
+
if @current_act&.actions&.reload&.empty?
|
87
|
+
@current_act.delete
|
88
|
+
@current_act = nil
|
86
89
|
end
|
87
90
|
end
|
88
91
|
|
92
|
+
|
89
93
|
def act_card?
|
90
94
|
self == Card::ActManager.act_card
|
91
95
|
end
|