card 1.20.0 → 1.20.1
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/card.gemspec +1 -1
- data/lib/card.rb +7 -3
- data/lib/card/act_manager/stage_director.rb +22 -10
- data/lib/card/cache/persistent.rb +15 -9
- data/lib/card/format/nest.rb +12 -5
- data/lib/card/format/nest/fetch.rb +2 -1
- data/lib/card/format/render.rb +5 -2
- data/lib/card/set/event.rb +7 -1
- data/lib/card/subcards.rb +3 -3
- data/lib/card/view/cache.rb +1 -1
- data/lib/card/view/fetch.rb +17 -5
- data/lib/card/view/options.rb +52 -26
- data/lib/cardio.rb +2 -1
- data/mod/account/spec/set/right/account_spec.rb +17 -3
- data/mod/admin/set/self/admin.rb +0 -2
- data/mod/admin/spec/set/self/admin_spec.rb +14 -11
- data/mod/bootstrap/set/all/bootstrap/helper.rb +27 -29
- data/mod/carrierwave/set/type/file.rb +1 -1
- data/mod/carrierwave/set/type/image.rb +18 -6
- data/mod/core/set/all/collection.rb +33 -7
- data/mod/core/set/all/fetch.rb +16 -3
- data/mod/core/set/all/permissions.rb +6 -12
- data/mod/core/set/all/trash.rb +3 -1
- data/mod/core/spec/set/all/collection_spec.rb +9 -8
- data/mod/email/set/all/notify.rb +27 -17
- data/mod/email/set/right/follow.rb +49 -36
- data/mod/email/set/type/email_template.rb +25 -69
- data/mod/email/set/type/email_template/email_config.rb +63 -0
- data/mod/email/set/type_plus_right/user/follow.rb +3 -3
- data/mod/machines/lib/stylesheets/style_cards.scss +292 -0
- data/mod/pointer/set/abstract/01_pointer.rb +8 -8
- data/mod/pointer/set/abstract/01_pointer/edit.rb +6 -2
- data/mod/prosemirror_editor/lib/javascript/script_prosemirror.js +12283 -11605
- data/mod/prosemirror_editor/lib/javascript/script_prosemirror_config.js.coffee +1 -1
- data/mod/standard/set/abstract/01_search_params.rb +1 -1
- data/mod/standard/set/abstract/search/paging.rb +4 -4
- data/mod/standard/set/all/comment.rb +67 -47
- data/mod/standard/set/all/links.rb +2 -2
- data/mod/standard/set/all/rich_html/content.rb +1 -1
- data/mod/standard/set/all/rich_html/editing.rb +3 -2
- data/mod/standard/set/all/rich_html/form.rb +21 -12
- data/mod/standard/set/all/rich_html/header.rb +9 -0
- data/mod/standard/set/all/rich_html/menu.rb +16 -12
- data/mod/standard/set/all/rich_html/toolbar.rb +140 -130
- data/mod/standard/set/all/rich_html/wrapper.rb +11 -1
- data/mod/standard/set/rstar/rules_editor.rb +2 -34
- data/mod/standard/set/self/search.rb +1 -1
- data/mod/standard/set/type/set.rb +4 -4
- data/mod/standard/spec/set/type/email_template/email_config_spec.rb +218 -0
- data/mod/standard/spec/set/type/email_template_spec.rb +3 -185
- data/spec/lib/card/cache_spec.rb +0 -1
- data/spec/lib/card/format/render_spec.rb +19 -0
- data/spec/lib/card/stage_director_spec.rb +1 -1
- data/tmpsets/set/mod001-core/all/actify.rb +5 -6
- data/tmpsets/set/mod001-core/all/fetch.rb +14 -12
- data/tmpsets/set/mod001-core/all/name.rb +1 -1
- data/tmpsets/set/mod001-core/all/permissions.rb +12 -22
- data/tmpsets/set/mod001-core/all/tracked_attributes.rb +76 -0
- data/tmpsets/set/mod001-core/all/utils.rb +40 -3
- data/tmpsets/set/mod002-history/all/history.rb +1 -2
- data/tmpsets/set/mod008-solid_cache/abstract/solid_cache.rb +1 -1
- data/tmpsets/set/mod013-carrierwave/abstract/attachment.rb +282 -0
- data/tmpsets/set/mod013-carrierwave/type/file.rb +155 -0
- data/tmpsets/set/mod013-carrierwave/type/image.rb +96 -0
- data/tmpsets/set/mod014-admin/self/admin.rb +113 -0
- data/tmpsets/set/mod014-admin/self/admin_info.rb +110 -0
- data/tmpsets/set/mod014-admin/self/version.rb +15 -0
- data/tmpsets/set/mod015-developer/all/event_viz.rb +59 -0
- data/tmpsets/set/mod015-developer/all/view_viz.rb +30 -0
- data/tmpsets/set/mod015-developer/right/debug.rb +96 -0
- metadata +15 -2
data/spec/lib/card/cache_spec.rb
CHANGED
@@ -0,0 +1,19 @@
|
|
1
|
+
describe Card::Format::Render do
|
2
|
+
describe "view cache" do
|
3
|
+
before { Cardio.config.view_cache = true }
|
4
|
+
|
5
|
+
let(:cache_key) do
|
6
|
+
"a-Card::Format::HtmlFormat-normal-home_view:content;"\
|
7
|
+
"nest_name:A;nest_syntax:A|content;view:contentcontent:show"
|
8
|
+
end
|
9
|
+
|
10
|
+
subject { Card::Cache[Card::View] }
|
11
|
+
|
12
|
+
it "can be changed with nest option" do
|
13
|
+
is_expected.to receive(:fetch).with cache_key
|
14
|
+
render_content "{{A|content}}"
|
15
|
+
is_expected.not_to receive(:fetch)
|
16
|
+
render_content "{{A|cache:never}}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -52,12 +52,12 @@ def valid?(*)
|
|
52
52
|
act { super }
|
53
53
|
end
|
54
54
|
|
55
|
-
def update_attributes
|
56
|
-
act
|
55
|
+
def update_attributes(*)
|
56
|
+
act { super }
|
57
57
|
end
|
58
58
|
|
59
|
-
def update_attributes!
|
60
|
-
act
|
59
|
+
def update_attributes!(*)
|
60
|
+
act { super }
|
61
61
|
end
|
62
62
|
|
63
63
|
def abortable
|
@@ -88,8 +88,7 @@ def with_transaction_returning_status
|
|
88
88
|
end
|
89
89
|
|
90
90
|
event :notable_exception_raised do
|
91
|
-
|
92
|
-
Rails.logger.debug "#{error.message}\n#{error.backtrace * "\n "}"
|
91
|
+
Rails.logger.debug "BT: #{Card::Error.current.backtrace * "\n "}"
|
93
92
|
end
|
94
93
|
|
95
94
|
def success
|
@@ -11,18 +11,20 @@ module ClassMethods
|
|
11
11
|
# * database
|
12
12
|
# * virtual cards
|
13
13
|
#
|
14
|
-
# @param
|
15
|
-
# one
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# If you pass more then one mark they get
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
14
|
+
# @param mark [Integer, String, Card::Name, Symbol, Array]
|
15
|
+
# one of three unique identifiers
|
16
|
+
# 1. a numeric id (Integer)
|
17
|
+
# 2. a name/key (String or Card::Name)
|
18
|
+
# 3. a codename (Symbol)
|
19
|
+
# or any combination of those. If you pass more then one mark they get
|
20
|
+
# joined with a '+'
|
21
|
+
# @param options [Hash]
|
22
|
+
# Options:
|
23
|
+
# :skip_virtual Real cards only
|
24
|
+
# :skip_modules Don't load Set modules
|
25
|
+
# :look_in_trash Return trashed card objects
|
26
|
+
# :local_only Use only local cache for lookup and storing
|
27
|
+
# new: { opts for Card#new } Return a new card when not found
|
26
28
|
#
|
27
29
|
# @return [Card]
|
28
30
|
def fetch *args
|
@@ -56,11 +56,11 @@ def update_subcard_names cardname
|
|
56
56
|
# and self is a subcard as well that changed from +B to A+B then
|
57
57
|
# +C should change to A+B+C. #replace_part doesn't work in this case
|
58
58
|
# because the old name +B is not a part of +C
|
59
|
+
# name_to_replace =
|
59
60
|
name_to_replace =
|
60
61
|
if subcard.cardname.junction? &&
|
61
62
|
subcard.cardname.parts.first.empty? &&
|
62
63
|
cardname.parts.first.present?
|
63
|
-
# replace the empty part
|
64
64
|
"".to_name
|
65
65
|
else
|
66
66
|
name
|
@@ -187,38 +187,28 @@ event :set_field_read_rules,
|
|
187
187
|
end
|
188
188
|
end
|
189
189
|
|
190
|
-
|
191
|
-
|
192
|
-
|
190
|
+
def update_read_rule
|
191
|
+
Card.record_timestamps = false
|
192
|
+
reset_patterns # why is this needed?
|
193
|
+
rcard_id, rclass = permission_rule_id_and_class :read
|
194
|
+
# these two are just to make sure vals are correct on current object
|
195
|
+
self.read_rule_id = rcard_id
|
196
|
+
self.read_rule_class = rclass
|
197
|
+
Card.where(id: id).update_all read_rule_id: rcard_id, read_rule_class: rclass
|
198
|
+
expire_hard
|
199
|
+
|
200
|
+
# currently doing a brute force search for every card that may be impacted.
|
201
|
+
# may want to optimize(?)
|
193
202
|
Auth.as_bot do
|
194
203
|
fields.each do |field|
|
195
204
|
field.update_read_rule if field.rule(:read) == "_left"
|
196
205
|
end
|
197
206
|
end
|
198
|
-
end
|
199
207
|
|
200
|
-
def without_timestamps
|
201
|
-
Card.record_timestamps = false
|
202
|
-
yield
|
203
208
|
ensure
|
204
209
|
Card.record_timestamps = true
|
205
210
|
end
|
206
211
|
|
207
|
-
event :update_read_rule do
|
208
|
-
without_timestamps do
|
209
|
-
reset_patterns # why is this needed?
|
210
|
-
rcard_id, rclass = permission_rule_id_and_class :read
|
211
|
-
# these two are just to make sure vals are correct on current object
|
212
|
-
self.read_rule_id = rcard_id
|
213
|
-
self.read_rule_class = rclass
|
214
|
-
Card.where(id: id).update_all read_rule_id: rcard_id,
|
215
|
-
read_rule_class: rclass
|
216
|
-
expire_hard
|
217
|
-
|
218
|
-
update_field_read_rules
|
219
|
-
end
|
220
|
-
end
|
221
|
-
|
222
212
|
def add_to_read_rule_update_queue updates
|
223
213
|
@read_rule_update_queue = Array.wrap(@read_rule_update_queue).concat updates
|
224
214
|
end
|
@@ -73,6 +73,82 @@ event :set_content, :store, on: :save do
|
|
73
73
|
reset_patterns_if_rule true
|
74
74
|
end
|
75
75
|
|
76
|
+
# FIXME: the following don't really belong here, but they have to come after
|
77
|
+
# the reference stuff. we need to organize a bit!
|
78
|
+
|
79
|
+
event :update_ruled_cards, :finalize do
|
80
|
+
if is_rule?
|
81
|
+
# warn "updating ruled cards for #{name}"
|
82
|
+
self.class.clear_rule_cache
|
83
|
+
set = rule_set
|
84
|
+
|
85
|
+
if right_id == Card::ReadID && (name_changed? || trash_changed?)
|
86
|
+
update_read_ruled_cards set
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def update_read_rules_of_set_members_not_governed_by_narrower_rules set
|
92
|
+
return {} if trash || !set || !(set_class = set.tag) ||
|
93
|
+
!(class_id = set_class.id)
|
94
|
+
in_set = {}
|
95
|
+
rule_class_ids = set_patterns.map(&:pattern_id)
|
96
|
+
Auth.as_bot do
|
97
|
+
cur_index = rule_class_ids.index Card[read_rule_class].id
|
98
|
+
if (rule_class_index = rule_class_ids.index(class_id))
|
99
|
+
set.item_cards(limit: 0).each do |item_card|
|
100
|
+
in_set[item_card.key] = true
|
101
|
+
next if cur_index < rule_class_index
|
102
|
+
item_card.update_read_rule if cur_index >= rule_class_index
|
103
|
+
end
|
104
|
+
else
|
105
|
+
warn "No current rule index #{class_id}, #{rule_class_ids.inspect}"
|
106
|
+
end
|
107
|
+
end
|
108
|
+
in_set
|
109
|
+
end
|
110
|
+
|
111
|
+
def update_read_ruled_cards set
|
112
|
+
self.class.clear_read_rule_cache
|
113
|
+
Card.cache.reset # maybe be more surgical, just Auth.user related
|
114
|
+
expire # probably shouldn't be necessary,
|
115
|
+
# but was sometimes getting cached version when card should be in the
|
116
|
+
# trash. could be related to other bugs?
|
117
|
+
|
118
|
+
updated = update_read_rules_of_set_members_not_governed_by_narrower_rules set
|
119
|
+
|
120
|
+
# then find all cards with me as read_rule_id that were not just updated
|
121
|
+
# and regenerate their read_rules
|
122
|
+
return if new_card?
|
123
|
+
Card.search(read_rule_id: id) do |card|
|
124
|
+
card.update_read_rule unless updated[card.key]
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
event :process_read_rule_update_queue, :finalize do
|
129
|
+
Array.wrap(@read_rule_update_queue).each(&:update_read_rule)
|
130
|
+
@read_rule_update_queue = []
|
131
|
+
end
|
132
|
+
|
133
|
+
event :expire_related, :finalize do
|
134
|
+
subcards.keys.each do |key|
|
135
|
+
Card.cache.soft.delete key
|
136
|
+
end
|
137
|
+
expire # FIXME: where do we put this. Here it deletes @stage
|
138
|
+
reset_patterns
|
139
|
+
if is_structure?
|
140
|
+
structuree_names.each do |name|
|
141
|
+
Card.expire name
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
event :expire_related_names, before: :expire_related, changed: :name do
|
147
|
+
# FIXME: look for opportunities to avoid instantiating the following
|
148
|
+
descendants.each(&:expire)
|
149
|
+
name_referers.each(&:expire)
|
150
|
+
end
|
151
|
+
|
76
152
|
|
77
153
|
# ~~ below autogenerated; above pulled from /Users/ethan/dev/wagn/gem/card/mod/core/set/all/tracked_attributes.rb ~~
|
78
154
|
end;end;end;end;
|
@@ -8,6 +8,7 @@ module ClassMethods
|
|
8
8
|
Card::Action.delete_cardless
|
9
9
|
Card::Reference.unmap_if_referee_missing
|
10
10
|
Card::Reference.delete_if_referer_missing
|
11
|
+
Card.delete_tmp_files_of_cached_uploads
|
11
12
|
end
|
12
13
|
|
13
14
|
# deletes any file not associated with a real card.
|
@@ -43,6 +44,20 @@ module ClassMethods
|
|
43
44
|
sql_results.map(&:values).flatten.map(&:to_i)
|
44
45
|
end
|
45
46
|
|
47
|
+
def delete_tmp_files_of_cached_uploads
|
48
|
+
actions = Card::Action.find_by_sql "SELECT * FROM card_actions
|
49
|
+
INNER JOIN cards ON card_actions.card_id = cards.id
|
50
|
+
WHERE cards.type_id IN (#{Card::FileID}, #{Card::ImageID})
|
51
|
+
AND card_actions.draft = true"
|
52
|
+
actions.each do |action|
|
53
|
+
# we don't want to delete uploads in progress
|
54
|
+
if older_than_five_days?(action.created_at) && (card = action.card)
|
55
|
+
# we don't want to delete uploads in progress
|
56
|
+
card.delete_files_for_action action
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
46
61
|
def merge_list attribs, opts={}
|
47
62
|
unmerged = []
|
48
63
|
attribs.each do |row|
|
@@ -72,7 +87,7 @@ module ClassMethods
|
|
72
87
|
end
|
73
88
|
|
74
89
|
def merge name, attribs={}, opts={}
|
75
|
-
puts "merging #{name}"
|
90
|
+
# puts "merging #{name}"
|
76
91
|
card = fetch name, new: {}
|
77
92
|
[:image, :file].each do |attach|
|
78
93
|
next unless attribs[attach] && attribs[attach].is_a?(String)
|
@@ -85,11 +100,33 @@ module ClassMethods
|
|
85
100
|
end
|
86
101
|
end
|
87
102
|
|
88
|
-
def
|
89
|
-
|
103
|
+
def older_than_five_days? time
|
104
|
+
Time.now - time > 432_000
|
90
105
|
end
|
91
106
|
end
|
92
107
|
|
108
|
+
def debug_type
|
109
|
+
"#{type_code || ''}:#{type_id}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def to_s
|
113
|
+
"#<#{self.class.name}[#{debug_type}]#{attributes['name']}>"
|
114
|
+
end
|
115
|
+
|
116
|
+
def inspect
|
117
|
+
tags = []
|
118
|
+
tags << "trash" if trash
|
119
|
+
tags << "new" if new_card?
|
120
|
+
tags << "frozen" if frozen?
|
121
|
+
tags << "readonly" if readonly?
|
122
|
+
tags << "virtual" if @virtual
|
123
|
+
tags << "set_mods_loaded" if @set_mods_loaded
|
124
|
+
|
125
|
+
error_messages = errors.any? ? "<E*#{errors.full_messages * ', '}*>" : ""
|
126
|
+
|
127
|
+
"#<Card##{id}[#{debug_type}](#{name})#{error_messages}{#{tags * ','}}"
|
128
|
+
end
|
129
|
+
|
93
130
|
|
94
131
|
# ~~ below autogenerated; above pulled from /Users/ethan/dev/wagn/gem/card/mod/core/set/all/utils.rb ~~
|
95
132
|
end;end;end;end;
|
@@ -85,8 +85,7 @@ event :rollback_actions, :prepare_to_validate,
|
|
85
85
|
Env.params["action_ids"] = nil
|
86
86
|
update_attributes! revision
|
87
87
|
rollback_actions.each do |action|
|
88
|
-
|
89
|
-
action.card.try :rollback_to, action
|
88
|
+
action.card.try :symlink_to, action.id
|
90
89
|
end
|
91
90
|
clear_drafts
|
92
91
|
abort :success
|
@@ -31,7 +31,7 @@ module ClassMethods
|
|
31
31
|
# cards whose solid caches are expired because of the update.
|
32
32
|
# @param set_of_changed_card [set constant] a set of cards that triggers
|
33
33
|
# a cache update
|
34
|
-
# @
|
34
|
+
# @params args [Hash]
|
35
35
|
# @option args [Symbol, Array of symbols] :on the action(s)
|
36
36
|
# (:create, :update, or :delete) on which the cache update
|
37
37
|
# should be triggered. Default is all actions.
|
@@ -0,0 +1,282 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class Card; module Set; class Abstract; module Attachment; extend Card::Set
|
3
|
+
# ~~ above autogenerated; below pulled from /Users/ethan/dev/wagn/gem/card/mod/carrierwave/set/abstract/attachment.rb ~~
|
4
|
+
require "carrier_wave/cardmount"
|
5
|
+
|
6
|
+
def self.included host_class
|
7
|
+
host_class.extend CarrierWave::CardMount
|
8
|
+
end
|
9
|
+
|
10
|
+
event :select_file_revision, after: :select_action do
|
11
|
+
attachment.retrieve_from_store!(attachment.identifier)
|
12
|
+
end
|
13
|
+
|
14
|
+
event :upload_attachment, :prepare_to_validate,
|
15
|
+
on: :save, when: proc { |c| c.preliminary_upload? } do
|
16
|
+
save_original_filename # save original filename as comment in action
|
17
|
+
write_identifier # set db_content
|
18
|
+
# (needs original filename to determine extension)
|
19
|
+
store_attachment!
|
20
|
+
finalize_action # create Card::Change entry for db_content
|
21
|
+
|
22
|
+
card_id = new_card? ? upload_cache_card.id : id
|
23
|
+
@current_action.update_attributes! draft: true, card_id: card_id
|
24
|
+
success << {
|
25
|
+
target: (new_card? ? upload_cache_card : self),
|
26
|
+
type: type_name,
|
27
|
+
view: "preview_editor",
|
28
|
+
rev_id: current_action.id
|
29
|
+
}
|
30
|
+
abort :success
|
31
|
+
end
|
32
|
+
|
33
|
+
event :assign_attachment_on_create, :initialize,
|
34
|
+
after: :assign_action, on: :create,
|
35
|
+
when: proc { |c| c.save_preliminary_upload? } do
|
36
|
+
if (action = Card::Action.fetch(@action_id_of_cached_upload))
|
37
|
+
upload_cache_card.selected_action_id = action.id
|
38
|
+
upload_cache_card.select_file_revision
|
39
|
+
assign_attachment upload_cache_card.attachment.file, action.comment
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
event :assign_attachment_on_update, :initialize,
|
44
|
+
after: :assign_action, on: :update,
|
45
|
+
when: proc { |c| c.save_preliminary_upload? } do
|
46
|
+
if (action = Card::Action.fetch(@action_id_of_cached_upload))
|
47
|
+
uploaded_file =
|
48
|
+
with_selected_action_id(action.id) do
|
49
|
+
attachment.file
|
50
|
+
end
|
51
|
+
assign_attachment uploaded_file, action.comment
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def assign_attachment file, original_filename
|
56
|
+
send "#{attachment_name}=", file
|
57
|
+
write_identifier
|
58
|
+
@current_action.update_attributes! comment: original_filename
|
59
|
+
end
|
60
|
+
|
61
|
+
# we need a card id for the path so we have to update db_content when we have
|
62
|
+
# an id
|
63
|
+
event :correct_identifier, :finalize, on: :create do
|
64
|
+
update_column(:db_content, attachment.db_content(mod: load_from_mod))
|
65
|
+
expire
|
66
|
+
end
|
67
|
+
|
68
|
+
def file_ready_to_save?
|
69
|
+
attachment.file.present? &&
|
70
|
+
!preliminary_upload? &&
|
71
|
+
!save_preliminary_upload? &&
|
72
|
+
attachment_changed?
|
73
|
+
end
|
74
|
+
|
75
|
+
event :save_original_filename, :prepare_to_store,
|
76
|
+
when: proc { |c| c.file_ready_to_save? } do
|
77
|
+
return unless @current_action
|
78
|
+
@current_action.update_attributes! comment: original_filename
|
79
|
+
end
|
80
|
+
|
81
|
+
event :delete_cached_upload_file_on_create, :integrate,
|
82
|
+
on: :create, when: proc { |c| c.save_preliminary_upload? } do
|
83
|
+
if (action = Card::Action.fetch(@action_id_of_cached_upload))
|
84
|
+
upload_cache_card.delete_files_for_action action
|
85
|
+
action.delete
|
86
|
+
end
|
87
|
+
clear_upload_cache_dir_for_new_cards
|
88
|
+
end
|
89
|
+
|
90
|
+
event :delete_cached_upload_file_on_update, :integrate,
|
91
|
+
on: :update, when: proc { |c| c.save_preliminary_upload? } do
|
92
|
+
if (action = Card::Action.fetch(@action_id_of_cached_upload))
|
93
|
+
delete_files_for_action action
|
94
|
+
action.delete
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
event :validate_file_exist, :validate, on: :create do
|
99
|
+
unless attachment.file.present? || empty_ok?
|
100
|
+
errors.add attachment_name, "is missing"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
event :write_identifier, after: :save_original_filename do
|
105
|
+
self.content = attachment.db_content(mod: load_from_mod)
|
106
|
+
end
|
107
|
+
|
108
|
+
def item_names _args={} # needed for flexmail attachments. hacky.
|
109
|
+
[cardname]
|
110
|
+
end
|
111
|
+
|
112
|
+
def original_filename
|
113
|
+
attachment.original_filename
|
114
|
+
end
|
115
|
+
|
116
|
+
def unfilled?
|
117
|
+
!attachment.present? && !save_preliminary_upload? && !subcards.present?
|
118
|
+
end
|
119
|
+
|
120
|
+
def preliminary_upload?
|
121
|
+
Card::Env && Card::Env.params[:attachment_upload]
|
122
|
+
end
|
123
|
+
|
124
|
+
def save_preliminary_upload?
|
125
|
+
@action_id_of_cached_upload.present?
|
126
|
+
end
|
127
|
+
|
128
|
+
def attachment_changed?
|
129
|
+
send "#{attachment_name}_changed?"
|
130
|
+
end
|
131
|
+
|
132
|
+
def create_versions?
|
133
|
+
true
|
134
|
+
end
|
135
|
+
|
136
|
+
# used for uploads for new cards until the new card is created
|
137
|
+
def upload_cache_card
|
138
|
+
@upload_cache_card ||= Card["new_#{attachment_name}".to_sym]
|
139
|
+
end
|
140
|
+
|
141
|
+
# action id of the cached upload
|
142
|
+
attr_writer :action_id_of_cached_upload
|
143
|
+
|
144
|
+
attr_reader :action_id_of_cached_upload
|
145
|
+
|
146
|
+
attr_writer :empty_ok
|
147
|
+
|
148
|
+
def empty_ok?
|
149
|
+
@empty_ok
|
150
|
+
end
|
151
|
+
|
152
|
+
def load_from_mod= value
|
153
|
+
@mod = value
|
154
|
+
write_identifier
|
155
|
+
@store_in_mod = true if value
|
156
|
+
end
|
157
|
+
|
158
|
+
def load_from_mod
|
159
|
+
@mod
|
160
|
+
end
|
161
|
+
|
162
|
+
def store_dir
|
163
|
+
if @store_in_mod
|
164
|
+
mod_dir
|
165
|
+
else
|
166
|
+
upload_dir
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def retrieve_dir
|
171
|
+
if mod_file?
|
172
|
+
mod_dir
|
173
|
+
else
|
174
|
+
upload_dir
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# place for files of regular file cards
|
179
|
+
def upload_dir
|
180
|
+
if id
|
181
|
+
"#{Card.paths['files'].existent.first}/#{id}"
|
182
|
+
else
|
183
|
+
tmp_upload_dir
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
# place for files if card doesn't have an id yet
|
188
|
+
def tmp_upload_dir _action_id=nil
|
189
|
+
"#{Card.paths['files'].existent.first}/#{upload_cache_card.id}"
|
190
|
+
end
|
191
|
+
|
192
|
+
# place for files of mod file cards
|
193
|
+
def mod_dir
|
194
|
+
mod = @mod || mod_file?
|
195
|
+
Card.paths["mod"].to_a.each do |mod_path|
|
196
|
+
dir = File.join(mod_path, mod, "file", codename)
|
197
|
+
return dir if Dir.exist? dir
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def mod_file?
|
202
|
+
return @mod if @store_in_mod
|
203
|
+
# when db_content was changed assume that it's no longer a mod file
|
204
|
+
return if db_content_changed? || !content.present?
|
205
|
+
case content
|
206
|
+
when %r{^:[^/]+/([^.]+)} then Regexp.last_match(1) # current mod_file format
|
207
|
+
when /^\~/ then false # current id file format
|
208
|
+
else
|
209
|
+
if (lines = content.split("\n")) && (lines.size == 4)
|
210
|
+
# old format, still used in card_changes.
|
211
|
+
lines.last
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
def assign_set_specific_attributes
|
217
|
+
# reset content if we really have something to upload
|
218
|
+
if @set_specific.present? && @set_specific[attachment_name.to_s].present?
|
219
|
+
self.content = nil
|
220
|
+
end
|
221
|
+
super
|
222
|
+
end
|
223
|
+
|
224
|
+
def clear_upload_cache_dir_for_new_cards
|
225
|
+
Dir.entries(tmp_upload_dir).each do |filename|
|
226
|
+
if filename =~ /^\d+/
|
227
|
+
path = File.join(tmp_upload_dir, filename)
|
228
|
+
FileUtils.rm path if Card.older_than_five_days? File.ctime(path)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
232
|
+
|
233
|
+
def delete_files_for_action action
|
234
|
+
with_selected_action_id(action.id) do
|
235
|
+
FileUtils.rm attachment.file.path
|
236
|
+
attachment.versions.each_value do |version|
|
237
|
+
FileUtils.rm version.path
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
# create filesystem links to files from prior action
|
243
|
+
def symlink_to prior_action_id
|
244
|
+
return unless prior_action_id != last_action_id
|
245
|
+
save_action_id = selected_action_id
|
246
|
+
links = {}
|
247
|
+
|
248
|
+
self.selected_action_id = prior_action_id
|
249
|
+
attachment.versions.each do |name, version|
|
250
|
+
links[name] = version.store_path
|
251
|
+
end
|
252
|
+
original = attachment.store_path
|
253
|
+
|
254
|
+
self.selected_action_id = last_action_id
|
255
|
+
attachment.versions.each do |name, version|
|
256
|
+
::File.symlink links[name], version.store_path
|
257
|
+
end
|
258
|
+
::File.symlink original, attachment.store_path
|
259
|
+
|
260
|
+
self.selected_action_id = save_action_id
|
261
|
+
end
|
262
|
+
|
263
|
+
def attachment_format ext
|
264
|
+
if ext.present? && attachment && (original_ext = attachment.extension)
|
265
|
+
if ["file", original_ext].member? ext
|
266
|
+
original_ext
|
267
|
+
elsif (exts = MIME::Types[attachment.content_type])
|
268
|
+
if exts.find { |mt| mt.extensions.member? ext }
|
269
|
+
ext
|
270
|
+
else
|
271
|
+
exts[0].extensions[0]
|
272
|
+
end
|
273
|
+
end
|
274
|
+
end
|
275
|
+
rescue => e
|
276
|
+
Rails.logger.info "attachment_format issue: #{e.message}"
|
277
|
+
nil
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
# ~~ below autogenerated; above pulled from /Users/ethan/dev/wagn/gem/card/mod/carrierwave/set/abstract/attachment.rb ~~
|
282
|
+
end;end;end;end;
|