card-mod-carrierwave 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,85 @@
1
+ # action id of the cached upload
2
+ attr_accessor :action_id_of_cached_upload
3
+
4
+ def actionable?
5
+ super || preliminary_upload?
6
+ end
7
+
8
+ event :prepare_attachment, :prepare_to_validate, on: :save, when: :preliminary_upload? do
9
+ save_original_filename # save original filename as comment in action
10
+ write_identifier # set db_content
11
+ # (needs original filename to determine extension)
12
+ store_attachment!
13
+ store_card_changes
14
+ # finalize_action # create Card::Change entry for db_content
15
+
16
+ card_id = new_card? ? upload_cache_card.id : id
17
+ @current_action.update! draft: true, card_id: card_id
18
+ success << {
19
+ target: (new_card? ? upload_cache_card : self),
20
+ type: type_name,
21
+ view: "preview_editor",
22
+ rev_id: current_action.id
23
+ }
24
+ abort :success
25
+ end
26
+
27
+ event :assign_attachment_on_create, :initialize,
28
+ after: :assign_action, on: :create, when: :save_preliminary_upload? do
29
+ return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
30
+ upload_cache_card.selected_action_id = action.id
31
+ upload_cache_card.select_file_revision
32
+ assign_attachment upload_cache_card.attachment.file, action.comment
33
+ end
34
+
35
+ event :assign_attachment_on_update, :initialize,
36
+ after: :assign_action, on: :update, when: :save_preliminary_upload? do
37
+ return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
38
+ uploaded_file = with_selected_action_id(action.id) { attachment.file }
39
+ assign_attachment uploaded_file, action.comment
40
+ end
41
+
42
+ def assign_attachment file, original_filename
43
+ send "#{attachment_name}=", file
44
+ write_identifier
45
+ @current_action&.update! comment: original_filename
46
+ end
47
+
48
+ event :delete_cached_upload_file_on_create, :integrate,
49
+ on: :create, when: :save_preliminary_upload? do
50
+ return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
51
+ upload_cache_card.delete_files_for_action action
52
+ action.delete
53
+ end
54
+
55
+ # at some point uploaded files of canceled file card creation
56
+ # should be deleted. We do this when ever an new file is created.
57
+ event :clear_draft_files, :integrate_with_delay, priority: 100, on: :create do
58
+ Card.delete_tmp_files_of_cached_uploads
59
+ end
60
+
61
+ event :delete_cached_upload_file_on_update, :integrate,
62
+ on: :update, when: :save_preliminary_upload? do
63
+ return unless (action = Card::Action.fetch(@action_id_of_cached_upload))
64
+ delete_files_for_action action
65
+ action.delete
66
+ end
67
+
68
+ # used for uploads for new cards until the new card is created
69
+ def upload_cache_card
70
+ cache_card_codename = "new_#{attachment_name}"
71
+ @upload_cache_card ||= Card::Codename.card(cache_card_codename) { Card[:new_file] }
72
+ end
73
+
74
+ def preliminary_upload?
75
+ Card::Env && Card::Env.params[:attachment_upload]
76
+ end
77
+
78
+ def save_preliminary_upload?
79
+ @action_id_of_cached_upload.present?
80
+ end
81
+
82
+ # place for files if card doesn't have an id yet
83
+ def tmp_upload_dir _action_id=nil
84
+ "#{files_base_dir}/#{upload_cache_card.id}"
85
+ end
@@ -0,0 +1,3 @@
1
+ def no_upload?
2
+ web? || storage_type_from_config == :web
3
+ end
@@ -0,0 +1,41 @@
1
+ module ClassMethods
2
+ def update_all_storage_locations
3
+ Card.search(type_id: ["in", Card::FileID, Card::ImageID])
4
+ .each(&:update_storage_location!)
5
+ end
6
+
7
+ def delete_tmp_files_of_cached_uploads
8
+ cards_with_disposable_attachments do |card, action|
9
+ card.delete_files_for_action action
10
+ action.delete
11
+ end
12
+ end
13
+
14
+ def cards_with_disposable_attachments
15
+ draft_actions_with_attachment.each do |action|
16
+ # we don't want to delete uploads in progress
17
+ next unless old_enough?(action.created_at) && (card = action.card)
18
+ # we can't delete attachments we don't have write access to
19
+ next if card.read_only?
20
+
21
+ yield card, action
22
+ end
23
+ end
24
+
25
+ def old_enough? time, expiration_time=5.day.to_i
26
+ Time.now - time > expiration_time
27
+ end
28
+
29
+ def draft_actions_with_attachment
30
+ Card::Action.find_by_sql(
31
+ "SELECT * FROM card_actions "\
32
+ "INNER JOIN cards ON card_actions.card_id = cards.id "\
33
+ "WHERE cards.type_id IN (#{Card::FileID}, #{Card::ImageID}) "\
34
+ "AND card_actions.draft = true"
35
+ )
36
+ end
37
+
38
+ def count_cards_with_attachment
39
+ Card.search type_id: ["in", Card::FileID, Card::ImageID], return: :count
40
+ end
41
+ end
@@ -0,0 +1,23 @@
1
+ add_to_basket(
2
+ :tasks,
3
+ name: :update_file_storage_locations,
4
+ execute_policy: -> { Card.update_all_storage_locations },
5
+ stats: {
6
+ title: "cards with attachment",
7
+ count: -> { Card.count_cards_with_attachment }
8
+ # link_text: "update storage locations",
9
+ # task: "update_file_storage_locations"
10
+ }
11
+ )
12
+
13
+ add_to_basket(
14
+ :tasks,
15
+ name: :delete_upload_tmp_files,
16
+ execute_policy: -> { Card.delete_tmp_files_of_cached_uploads },
17
+ stats: {
18
+ title: "tmp files of canceled uploads",
19
+ count: -> { ::Card.draft_actions_with_attachment },
20
+ link_text: "delete tmp files",
21
+ task: "delete_tmp_files_of_cached_uploads"
22
+ }
23
+ )
@@ -0,0 +1,16 @@
1
+ format :html do
2
+ view :source do
3
+ source = card.type_id == Card::ImageID ? super() : nil
4
+ source.present? ? source : nest(:logo, view: :source, size: voo.size)
5
+ end
6
+
7
+ view :link_tag, perms: :none do
8
+ return unless (source = render :source, size: :small)
9
+ tag :link, rel: "shortcut icon", href: source
10
+ end
11
+
12
+ def raw_help_text
13
+ "A favicon (or shortcut icon) is a small image used by browsers to help identify "\
14
+ "your website. [[http://www.decko.org/favicon|How to customize your favicon]]"
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ format :html do
2
+ view :source, cache: :never do
3
+ super()
4
+ end
5
+
6
+ view :core, cache: :never do
7
+ super()
8
+ end
9
+
10
+ view :input, cache: :never do
11
+ super()
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ format :html do
2
+ view :source, cache: :never do
3
+ super()
4
+ end
5
+
6
+ view :core, cache: :never do
7
+ super()
8
+ end
9
+
10
+ view :input, cache: :never do
11
+ super()
12
+ end
13
+ end
@@ -0,0 +1,116 @@
1
+ attachment :file, uploader: CarrierWave::FileCardUploader
2
+
3
+ module SelectedAction
4
+ def select_action_by_params params
5
+ # skip action table lookups for current revision
6
+ rev_id = params[:rev_id]
7
+ super unless rev_id && rev_id == last_content_action_id
8
+ end
9
+
10
+ def last_content_action_id
11
+ return super if temporary_storage_type_change?
12
+ # find action id from content (saves lookups)
13
+ db_content.to_s.split(%r{[/\.]})[-2]
14
+ end
15
+ end
16
+ include SelectedAction
17
+
18
+ format do
19
+ view :source do
20
+ file = card.attachment
21
+ return "" unless file.valid?
22
+ contextualize_path file.url
23
+ end
24
+
25
+ view :core do
26
+ handle_source do |source|
27
+ card_url source
28
+ end
29
+ end
30
+
31
+ def short_content
32
+ number_to_human_size card.attachment.size
33
+ end
34
+
35
+ def handle_source
36
+ source = _render_source
37
+ return "" if source.blank?
38
+ block_given? ? yield(source) : source
39
+ rescue => e
40
+ Rails.logger.info "Error with file source: #{e.message}"
41
+ tr :file_error
42
+ end
43
+
44
+ def selected_version
45
+ card.attachment
46
+ end
47
+ end
48
+
49
+ format :file do
50
+ # NOCACHE because returns send_file args. not in love with this...
51
+ view :core, cache: :never do
52
+ # this means we only support known formats. dislike.
53
+ attachment_format = card.attachment_format(params[:format])
54
+ return _render_not_found unless attachment_format
55
+ return card.format(:html).render_core if card.remote_storage?
56
+ set_response_headers
57
+ args_for_send_file
58
+ end
59
+
60
+ def args_for_send_file
61
+ file = selected_version
62
+ [file.path, { type: file.content_type,
63
+ filename: "#{card.name.safe_key}#{file.extension}",
64
+ x_sendfile: true,
65
+ disposition: (params[:format] == "file" ? "attachment" : "inline") }]
66
+ end
67
+
68
+ def set_response_headers
69
+ return unless params[:explicit_file] && (response = controller&.response)
70
+ response.headers["Expires"] = 1.year.from_now.httpdate
71
+ # currently using default "private", because proxy servers could block
72
+ # needed permission checks
73
+ # r.headers["Cache-Control"] = "public"
74
+ end
75
+ end
76
+
77
+ format :html do
78
+ view :core do
79
+ handle_source do |source|
80
+ "<a href=\"#{source}\">#{tr :download, title: title_in_context(voo.title)}</a>"
81
+ end
82
+ end
83
+
84
+ view :input do
85
+ if card.no_upload?
86
+ text_field :content, class: "d0-card-content"
87
+ else
88
+ haml :file_chooser, action_text: file_chooser_action_text
89
+ end
90
+ end
91
+
92
+ view :preview_editor, unknown: true, cache: :never do
93
+ haml :preview_editor
94
+ end
95
+
96
+ def file_chooser_action_text
97
+ action = card.new_card? ? "Add" : "Replace"
98
+ "#{action} #{humanized_attachment_name}..."
99
+ end
100
+
101
+ def humanized_attachment_name
102
+ card.attachment_name.to_s.humanize
103
+ end
104
+
105
+ def preview
106
+ ""
107
+ end
108
+
109
+ def cached_upload_card_name
110
+ Card::Env.params[:attachment_upload].gsub(/\[\w+\]$/, "[action_id_of_cached_upload]")
111
+ end
112
+
113
+ def preview_editor_delete_text
114
+ tr :delete
115
+ end
116
+ end
@@ -0,0 +1,15 @@
1
+ .choose-file
2
+ = preview
3
+ %span.btn.btn-secondary.fileinput-button
4
+ = icon_tag "cloud_upload"
5
+ %span<
6
+ = action_text
7
+ %input.file-upload.slotter.form-control{ id: "card_#{card.type_code}",
8
+ name: "card[#{card.type_code}]",
9
+ type: "file" }
10
+ = hidden_field_tag "attachment_type_id", card.type_id
11
+ = hidden_field card.attachment_name, class: "attachment_card_name", value: ""
12
+ = hidden_field_tag 'file_card_name', card.name.url_key
13
+ #progress.progress.mb-2{ style: "display: none;" }
14
+ .progress-bar.progress-bar-success{ style: "width: 0%;" }
15
+ .chosen-file
@@ -0,0 +1,19 @@
1
+ .chosen-file
2
+ %input{ name: cached_upload_card_name, type: "hidden", value: card.selected_action_id }
3
+ %table.table.table-striped{ role: "presentation" }
4
+ %tbody.files
5
+ %tr.template-download.fade.show
6
+ %td
7
+ %span.preview
8
+ = preview
9
+ %td
10
+ %p.name
11
+ = card.original_filename
12
+ %td
13
+ %span.size
14
+ = number_to_human_size card.attachment.size
15
+ %td.float-right
16
+ %button.btn.btn-danger.delete.cancel-upload{ "data-type": "DELETE" }
17
+ = icon_tag :delete
18
+ %span
19
+ = preview_editor_delete_text
@@ -0,0 +1,101 @@
1
+ attachment :image, uploader: CarrierWave::ImageCardUploader
2
+
3
+ include File::SelectedAction
4
+
5
+ def create_versions? new_file
6
+ new_file.extension != "svg"
7
+ end
8
+
9
+ def svg?
10
+ image&.extension == ".svg"
11
+ end
12
+
13
+ format do
14
+ include File::Format
15
+
16
+ view :one_line_content do
17
+ _render_core size: :icon
18
+ end
19
+
20
+ def short_content
21
+ render_core size: :icon
22
+ end
23
+
24
+ view :source do
25
+ return card.content if card.web?
26
+ image = selected_version
27
+ return "" unless image.valid?
28
+ contextualize_path image.url
29
+ end
30
+
31
+ def selected_version
32
+ size = determine_image_size
33
+ if size && size != :original
34
+ card.image.versions[size]
35
+ else
36
+ card.image
37
+ end
38
+ end
39
+
40
+ def handle_source
41
+ super
42
+ end
43
+
44
+ def closed_size
45
+ :icon
46
+ end
47
+
48
+ def main_size
49
+ :large
50
+ end
51
+
52
+ def default_size
53
+ :medium
54
+ end
55
+
56
+ def determine_image_size
57
+ voo.size =
58
+ case
59
+ when nest_mode == :closed then closed_size
60
+ when voo.size.present? then voo.size.to_sym
61
+ when main? then main_size
62
+ else default_size
63
+ end
64
+ voo.size = :original if voo.size == :full
65
+ voo.size
66
+ end
67
+
68
+ view :inline do
69
+ _render_core
70
+ end
71
+ end
72
+
73
+ format :email_html do
74
+ view :inline, cache: :never do
75
+ handle_source do |source|
76
+ return source unless (mail = inherit :active_mail) &&
77
+ ::File.exist?(path = selected_version.path)
78
+ url = attach_image mail, path
79
+ image_tag url
80
+ end
81
+ end
82
+
83
+ def attach_image mail, path
84
+ mail.attachments.inline[path] = ::File.read path
85
+ mail.attachments[path].url
86
+ end
87
+ end
88
+
89
+ format :css do
90
+ view :core do
91
+ handle_source
92
+ end
93
+
94
+ view :content do # why is this necessary?
95
+ render_core
96
+ end
97
+ end
98
+
99
+ format :file do
100
+ include File::FileFormat
101
+ end