##// END OF EJS Templates
Feature 9867 Allow file upload in comment and add to issue history...
Jean-Philippe Lang -
r422:3f87f3c47a26
parent child
Show More
@@ -1,139 +1,159
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class IssuesController < ApplicationController
18 class IssuesController < ApplicationController
19 layout 'base', :except => :export_pdf
19 layout 'base', :except => :export_pdf
20 before_filter :find_project, :authorize
20 before_filter :find_project, :authorize
21
21
22 helper :custom_fields
22 helper :custom_fields
23 include CustomFieldsHelper
23 include CustomFieldsHelper
24 helper :ifpdf
24 helper :ifpdf
25 include IfpdfHelper
25 include IfpdfHelper
26
26
27 def show
27 def show
28 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
28 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
29 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
29 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
30 @journals_count = @issue.journals.count
30 @journals_count = @issue.journals.count
31 @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "#{Journal.table_name}.created_on desc")
31 @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "#{Journal.table_name}.created_on desc")
32 end
32 end
33
33
34 def history
34 def history
35 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on desc")
35 @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on desc")
36 @journals_count = @journals.length
36 @journals_count = @journals.length
37 end
37 end
38
38
39 def export_pdf
39 def export_pdf
40 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
40 @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
41 @options_for_rfpdf ||= {}
41 @options_for_rfpdf ||= {}
42 @options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf"
42 @options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf"
43 end
43 end
44
44
45 def edit
45 def edit
46 @priorities = Enumeration::get_values('IPRI')
46 @priorities = Enumeration::get_values('IPRI')
47 if request.get?
47 if request.get?
48 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
48 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
49 else
49 else
50 begin
50 begin
51 @issue.init_journal(self.logged_in_user)
51 @issue.init_journal(self.logged_in_user)
52 # Retrieve custom fields and values
52 # Retrieve custom fields and values
53 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
53 @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
54 @issue.custom_values = @custom_values
54 @issue.custom_values = @custom_values
55 @issue.attributes = params[:issue]
55 @issue.attributes = params[:issue]
56 if @issue.save
56 if @issue.save
57 flash[:notice] = l(:notice_successful_update)
57 flash[:notice] = l(:notice_successful_update)
58 redirect_to :action => 'show', :id => @issue
58 redirect_to :action => 'show', :id => @issue
59 end
59 end
60 rescue ActiveRecord::StaleObjectError
60 rescue ActiveRecord::StaleObjectError
61 # Optimistic locking exception
61 # Optimistic locking exception
62 flash[:notice] = l(:notice_locking_conflict)
62 flash[:notice] = l(:notice_locking_conflict)
63 end
63 end
64 end
64 end
65 end
65 end
66
66
67 def add_note
67 def add_note
68 unless params[:notes].empty?
68 unless params[:notes].empty?
69 journal = @issue.init_journal(self.logged_in_user, params[:notes])
69 journal = @issue.init_journal(self.logged_in_user, params[:notes])
70 if @issue.save
70 if @issue.save
71 flash[:notice] = l(:notice_successful_update)
71 flash[:notice] = l(:notice_successful_update)
72 Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
72 Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
73 redirect_to :action => 'show', :id => @issue
73 redirect_to :action => 'show', :id => @issue
74 return
74 return
75 end
75 end
76 end
76 end
77 show
77 show
78 render :action => 'show'
78 render :action => 'show'
79 end
79 end
80
80
81 def change_status
81 def change_status
82 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
82 @status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user
83 @new_status = IssueStatus.find(params[:new_status_id])
83 @new_status = IssueStatus.find(params[:new_status_id])
84 if params[:confirm]
84 if params[:confirm]
85 begin
85 begin
86 journal = @issue.init_journal(self.logged_in_user, params[:notes])
86 journal = @issue.init_journal(self.logged_in_user, params[:notes])
87 @issue.status = @new_status
87 @issue.status = @new_status
88 if @issue.update_attributes(params[:issue])
88 if @issue.update_attributes(params[:issue])
89 # Save attachments
90 params[:attachments].each { |file|
91 next unless file.size > 0
92 a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)
93 journal.details << JournalDetail.new(:property => 'attachment',
94 :prop_key => a.id,
95 :value => a.filename) unless a.new_record?
96 } if params[:attachments] and params[:attachments].is_a? Array
97
89 flash[:notice] = l(:notice_successful_update)
98 flash[:notice] = l(:notice_successful_update)
90 Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
99 Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
91 redirect_to :action => 'show', :id => @issue
100 redirect_to :action => 'show', :id => @issue
92 end
101 end
93 rescue ActiveRecord::StaleObjectError
102 rescue ActiveRecord::StaleObjectError
94 # Optimistic locking exception
103 # Optimistic locking exception
95 flash[:notice] = l(:notice_locking_conflict)
104 flash[:notice] = l(:notice_locking_conflict)
96 end
105 end
97 end
106 end
98 @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
107 @assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
99 end
108 end
100
109
101 def destroy
110 def destroy
102 @issue.destroy
111 @issue.destroy
103 redirect_to :controller => 'projects', :action => 'list_issues', :id => @project
112 redirect_to :controller => 'projects', :action => 'list_issues', :id => @project
104 end
113 end
105
114
106 def add_attachment
115 def add_attachment
107 # Save the attachments
116 # Save the attachments
108 @attachments = []
117 @attachments = []
118 journal = @issue.init_journal(self.logged_in_user)
109 params[:attachments].each { |file|
119 params[:attachments].each { |file|
110 next unless file.size > 0
120 next unless file.size > 0
111 a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)
121 a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)
112 @attachments << a unless a.new_record?
122 @attachments << a unless a.new_record?
123 journal.details << JournalDetail.new(:property => 'attachment',
124 :prop_key => a.id,
125 :value => a.filename) unless a.new_record?
113 } if params[:attachments] and params[:attachments].is_a? Array
126 } if params[:attachments] and params[:attachments].is_a? Array
127 journal.save if journal.details.any?
114 Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
128 Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
115 redirect_to :action => 'show', :id => @issue
129 redirect_to :action => 'show', :id => @issue
116 end
130 end
117
131
118 def destroy_attachment
132 def destroy_attachment
119 @issue.attachments.find(params[:attachment_id]).destroy
133 a = @issue.attachments.find(params[:attachment_id])
134 a.destroy
135 journal = @issue.init_journal(self.logged_in_user)
136 journal.details << JournalDetail.new(:property => 'attachment',
137 :prop_key => a.id,
138 :old_value => a.filename)
139 journal.save
120 redirect_to :action => 'show', :id => @issue
140 redirect_to :action => 'show', :id => @issue
121 end
141 end
122
142
123 # Send the file in stream mode
143 # Send the file in stream mode
124 def download
144 def download
125 @attachment = @issue.attachments.find(params[:attachment_id])
145 @attachment = @issue.attachments.find(params[:attachment_id])
126 send_file @attachment.diskfile, :filename => @attachment.filename
146 send_file @attachment.diskfile, :filename => @attachment.filename
127 rescue
147 rescue
128 render_404
148 render_404
129 end
149 end
130
150
131 private
151 private
132 def find_project
152 def find_project
133 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
153 @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
134 @project = @issue.project
154 @project = @issue.project
135 @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
155 @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
136 rescue ActiveRecord::RecordNotFound
156 rescue ActiveRecord::RecordNotFound
137 render_404
157 render_404
138 end
158 end
139 end
159 end
@@ -1,74 +1,86
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module IssuesHelper
18 module IssuesHelper
19
19
20 def show_detail(detail, no_html=false)
20 def show_detail(detail, no_html=false)
21 case detail.property
21 case detail.property
22 when 'attr'
22 when 'attr'
23 label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym)
23 label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym)
24 case detail.prop_key
24 case detail.prop_key
25 when 'due_date', 'start_date'
25 when 'due_date', 'start_date'
26 value = format_date(detail.value.to_date) if detail.value
26 value = format_date(detail.value.to_date) if detail.value
27 old_value = format_date(detail.old_value.to_date) if detail.old_value
27 old_value = format_date(detail.old_value.to_date) if detail.old_value
28 when 'status_id'
28 when 'status_id'
29 s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value
29 s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value
30 s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value
30 s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value
31 when 'assigned_to_id'
31 when 'assigned_to_id'
32 u = User.find_by_id(detail.value) and value = u.name if detail.value
32 u = User.find_by_id(detail.value) and value = u.name if detail.value
33 u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value
33 u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value
34 when 'priority_id'
34 when 'priority_id'
35 e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value
35 e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value
36 e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value
36 e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value
37 when 'category_id'
37 when 'category_id'
38 c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
38 c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
39 c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
39 c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
40 when 'fixed_version_id'
40 when 'fixed_version_id'
41 v = Version.find_by_id(detail.value) and value = v.name if detail.value
41 v = Version.find_by_id(detail.value) and value = v.name if detail.value
42 v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
42 v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
43 end
43 end
44 when 'cf'
44 when 'cf'
45 custom_field = CustomField.find_by_id(detail.prop_key)
45 custom_field = CustomField.find_by_id(detail.prop_key)
46 if custom_field
46 if custom_field
47 label = custom_field.name
47 label = custom_field.name
48 value = format_value(detail.value, custom_field.field_format) if detail.value
48 value = format_value(detail.value, custom_field.field_format) if detail.value
49 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
49 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
50 end
50 end
51 when 'attachment'
52 label = l(:label_attachment)
51 end
53 end
52
54
53 label ||= detail.prop_key
55 label ||= detail.prop_key
54 value ||= detail.value
56 value ||= detail.value
55 old_value ||= detail.old_value
57 old_value ||= detail.old_value
56
58
57 unless no_html
59 unless no_html
58 label = content_tag('strong', label)
60 label = content_tag('strong', label)
59 old_value = content_tag("i", h(old_value)) if detail.old_value
61 old_value = content_tag("i", h(old_value)) if detail.old_value
60 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
62 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
61 value = content_tag("i", h(value)) if value
63 value = content_tag("i", h(value)) if value
62 end
64 end
63
65
64 if detail.value and !detail.value.to_s.empty?
66 if detail.value and !detail.value.to_s.empty?
65 if old_value
67 case detail.property
66 label + " " + l(:text_journal_changed, old_value, value)
68 when 'attr', 'cf'
67 else
69 if old_value
68 label + " " + l(:text_journal_set_to, value)
70 label + " " + l(:text_journal_changed, old_value, value)
71 else
72 label + " " + l(:text_journal_set_to, value)
73 end
74 when 'attachment'
75 "#{label} #{value} #{l(:label_added)}"
69 end
76 end
70 else
77 else
71 label + " " + l(:text_journal_deleted) + " (#{old_value})"
78 case detail.property
79 when 'attr', 'cf'
80 label + " " + l(:text_journal_deleted) + " (#{old_value})"
81 when 'attachment'
82 "#{label} #{old_value} #{l(:label_deleted)}"
83 end
72 end
84 end
73 end
85 end
74 end
86 end
@@ -1,37 +1,43
1 <h2><%=l(:label_issue)%> #<%= @issue.id %>: <%=h @issue.subject %></h2>
1 <h2><%=l(:label_issue)%> #<%= @issue.id %>: <%=h @issue.subject %></h2>
2
2
3 <%= error_messages_for 'issue' %>
3 <%= error_messages_for 'issue' %>
4 <% form_tag({:action => 'change_status', :id => @issue}, :class => "tabular") do %>
4 <% form_tag({:action => 'change_status', :id => @issue}, :multipart => true, :class => "tabular") do %>
5
5
6 <%= hidden_field_tag 'confirm', 1 %>
6 <%= hidden_field_tag 'confirm', 1 %>
7 <%= hidden_field_tag 'new_status_id', @new_status.id %>
7 <%= hidden_field_tag 'new_status_id', @new_status.id %>
8
8
9 <div class="box">
9 <div class="box">
10 <p><label><%=l(:label_issue_status_new)%></label> <%= @new_status.name %></p>
10 <p><label><%=l(:label_issue_status_new)%></label> <%= @new_status.name %></p>
11
11
12 <p><label for="issue_assigned_to_id"><%=l(:field_assigned_to)%></label>
12 <p><label for="issue_assigned_to_id"><%=l(:field_assigned_to)%></label>
13 <select name="issue[assigned_to_id]">
13 <select name="issue[assigned_to_id]">
14 <option value=""></option>
14 <option value=""></option>
15 <%= options_from_collection_for_select @assignable_to, "id", "display_name", @issue.assigned_to_id %></p>
15 <%= options_from_collection_for_select @assignable_to, "id", "display_name", @issue.assigned_to_id %></p>
16 </select></p>
16 </select></p>
17
17
18
18
19 <p><label for="issue_done_ratio"><%=l(:field_done_ratio)%></label>
19 <p><label for="issue_done_ratio"><%=l(:field_done_ratio)%></label>
20 <%= select("issue", "done_ratio", ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) ) %>
20 <%= select("issue", "done_ratio", ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) ) %>
21 </select></p>
21 </select></p>
22
22
23
23
24 <p><label for="issue_fixed_version"><%=l(:field_fixed_version)%></label>
24 <p><label for="issue_fixed_version"><%=l(:field_fixed_version)%></label>
25 <select name="issue[fixed_version_id]">
25 <select name="issue[fixed_version_id]">
26 <option value="">--none--</option>
26 <option value="">--none--</option>
27 <%= options_from_collection_for_select @issue.project.versions, "id", "name", @issue.fixed_version_id %>
27 <%= options_from_collection_for_select @issue.project.versions, "id", "name", @issue.fixed_version_id %>
28 </select></p>
28 </select></p>
29
29
30 <p><label for="notes"><%= l(:field_notes) %></label>
30 <p><label for="notes"><%= l(:field_notes) %></label>
31 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %></p>
31 <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %></p>
32
32
33 <% if authorize_for('issues', 'add_attachment') %>
34 <p id="attachments_p"><label><%=l(:label_attachment_new)%>
35 <%= image_to_function "add.png", "addFileField();return false" %></label>
36 <%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p>
37 <% end %>
38
33 </div>
39 </div>
34
40
35 <%= hidden_field 'issue', 'lock_version' %>
41 <%= hidden_field 'issue', 'lock_version' %>
36 <%= submit_tag l(:button_save) %>
42 <%= submit_tag l(:button_save) %>
37 <% end %>
43 <% end %>
General Comments 0
You need to be logged in to leave comments. Login now