diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-02-16 21:00:11 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2012-02-16 21:00:11 +0000 |
commit | d4e6355eb3f220787e9374eeef6fb496f213f0d1 (patch) | |
tree | 1fe20acbf595c1df2407cc563ed37acf74292c10 /app | |
parent | a8f98bb74903954f28c4299f4ea7a7279d9028dd (diff) | |
download | redmine-d4e6355eb3f220787e9374eeef6fb496f213f0d1.tar.gz redmine-d4e6355eb3f220787e9374eeef6fb496f213f0d1.zip |
Better handling of attachments when issue validation fails (#10253).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@8891 e93f8b46-1217-0410-a6f0-8f06a7374b81
Diffstat (limited to 'app')
-rw-r--r-- | app/controllers/issues_controller.rb | 3 | ||||
-rw-r--r-- | app/models/attachment.rb | 61 | ||||
-rw-r--r-- | app/models/issue.rb | 23 | ||||
-rw-r--r-- | app/views/attachments/_form.html.erb | 8 | ||||
-rw-r--r-- | app/views/issues/_edit.html.erb | 2 | ||||
-rw-r--r-- | app/views/issues/new.html.erb | 2 |
6 files changed, 56 insertions, 43 deletions
diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 16a0fe723..7adad0008 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -149,8 +149,8 @@ class IssuesController < ApplicationController def create call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) + @issue.save_attachments(params[:attachments]) if @issue.save - attachments = Attachment.attach_files(@issue, params[:attachments]) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| format.html { @@ -181,6 +181,7 @@ class IssuesController < ApplicationController def update return unless update_issue_from_params + @issue.save_attachments(params[:attachments]) saved = false begin saved = @issue.save_issue_with_child_records(params, @time_entry) diff --git a/app/models/attachment.rb b/app/models/attachment.rb index d57422db7..7fb9ed379 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -21,7 +21,7 @@ class Attachment < ActiveRecord::Base belongs_to :container, :polymorphic => true belongs_to :author, :class_name => "User", :foreign_key => "author_id" - validates_presence_of :container, :filename, :author + validates_presence_of :filename, :author validates_length_of :filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255 validate :validate_max_file_size @@ -49,6 +49,15 @@ class Attachment < ActiveRecord::Base before_save :files_to_final_location after_destroy :delete_from_disk + def container_with_blank_type_check + if container_type.blank? + nil + else + container_without_blank_type_check + end + end + alias_method_chain :container, :blank_type_check unless method_defined?(:container_without_blank_type_check) + # Returns an unsaved copy of the attachment def copy(attributes=nil) copy = self.class.new @@ -121,15 +130,15 @@ class Attachment < ActiveRecord::Base end def project - container.project + container.try(:project) end def visible?(user=User.current) - container.attachments_visible?(user) + container && container.attachments_visible?(user) end def deletable?(user=User.current) - container.attachments_deletable?(user) + container && container.attachments_deletable?(user) end def image? @@ -149,32 +158,31 @@ class Attachment < ActiveRecord::Base File.readable?(diskfile) end + # Returns the attachment token + def token + "#{id}.#{digest}" + end + + # Finds an attachment that matches the given token and that has no container + def self.find_by_token(token) + if token.to_s =~ /^(\d+)\.([0-9a-f]+)$/ + attachment_id, attachment_digest = $1, $2 + attachment = Attachment.first(:conditions => {:id => attachment_id, :digest => attachment_digest}) + if attachment && attachment.container.nil? + attachment + end + end + end + # Bulk attaches a set of files to an object # # Returns a Hash of the results: # :files => array of the attached files # :unsaved => array of the files that could not be attached def self.attach_files(obj, attachments) - attached = [] - if attachments && attachments.is_a?(Hash) - attachments.each_value do |attachment| - file = attachment['file'] - next unless file && file.size > 0 - a = Attachment.create(:container => obj, - :file => file, - :description => attachment['description'].to_s.strip, - :author => User.current) - obj.attachments << a - - if a.new_record? - obj.unsaved_attachments ||= [] - obj.unsaved_attachments << a - else - attached << a - end - end - end - {:files => attached, :unsaved => obj.unsaved_attachments} + result = obj.save_attachments(attachments, User.current) + obj.attach_saved_attachments + result end def self.latest_attach(attachments, filename) @@ -183,6 +191,11 @@ class Attachment < ActiveRecord::Base } end + def self.prune(age=1.day) + attachments = Attachment.all(:conditions => ["created_on < ? AND (container_type IS NULL OR container_type = ''", Time.now - age]) + attachments.each(&:destroy) + end + private # Physically deletes the file from the file system diff --git a/app/models/issue.rb b/app/models/issue.rb index 2750d7f63..eced77684 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -680,8 +680,7 @@ class Issue < ActiveRecord::Base s end - # Saves an issue, time_entry, attachments, and a journal from the parameters - # Returns false if save fails + # Saves an issue and a time_entry from the parameters def save_issue_with_child_records(params, existing_time_entry=nil) Issue.transaction do if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, project) @@ -694,21 +693,13 @@ class Issue < ActiveRecord::Base self.time_entries << @time_entry end - if valid? - attachments = Attachment.attach_files(self, params[:attachments]) + # TODO: Rename hook + Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + if save # TODO: Rename hook - Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) - begin - if save - # TODO: Rename hook - Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) - else - raise ActiveRecord::Rollback - end - rescue ActiveRecord::StaleObjectError - attachments[:files].each(&:destroy) - raise ActiveRecord::StaleObjectError - end + Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + else + raise ActiveRecord::Rollback end end end diff --git a/app/views/attachments/_form.html.erb b/app/views/attachments/_form.html.erb index a7c463989..464d3a2d7 100644 --- a/app/views/attachments/_form.html.erb +++ b/app/views/attachments/_form.html.erb @@ -1,3 +1,11 @@ +<% if defined?(container) && container && container.saved_attachments %> + <% container.saved_attachments.each_with_index do |attachment, i| %> + <span class="icon icon-attachment" style="display:block; line-height:1.5em;"> + <%= h(attachment.filename) %> (<%= number_to_human_size(attachment.filesize) %>) + <%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.id}.#{attachment.digest}" %> + </span> + <% end %> +<% end %> <span id="attachments_fields"> <span> <%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil, :class => 'file', diff --git a/app/views/issues/_edit.html.erb b/app/views/issues/_edit.html.erb index 809194779..690fa9386 100644 --- a/app/views/issues/_edit.html.erb +++ b/app/views/issues/_edit.html.erb @@ -31,7 +31,7 @@ <%= wikitoolbar_for 'notes' %> <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> - <p><%=l(:label_attachment_plural)%><br /><%= render :partial => 'attachments/form' %></p> + <p><%=l(:label_attachment_plural)%><br /><%= render :partial => 'attachments/form', :locals => {:container => @issue} %></p> </fieldset> </div> diff --git a/app/views/issues/new.html.erb b/app/views/issues/new.html.erb index f8da7e926..11268214f 100644 --- a/app/views/issues/new.html.erb +++ b/app/views/issues/new.html.erb @@ -18,7 +18,7 @@ </p> <% end %> - <p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form' %></p> + <p id="attachments_form"><%= label_tag('attachments[1][file]', l(:label_attachment_plural))%><%= render :partial => 'attachments/form', :locals => {:container => @issue} %></p> <% if @issue.safe_attribute? 'watcher_user_ids' -%> <p id="watchers_form"><label><%= l(:label_issue_watchers) %></label> |