Merged IssuesController change_status and add_note actions.
The 'Change status' specific form removed and now accessible from issue/show view with no additional request (click on 'Update' to show the form). The 'Change issue status' permission is removed. To change the status, the user just needs to have either 'Edit' or 'Add note' permissions and some workflow transitions allowed. git-svn-id: http://redmine.rubyforge.org/svn/trunk@1043 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
4a729036bf
commit
976a31e941
|
@ -21,7 +21,7 @@ class IssuesController < ApplicationController
|
|||
before_filter :find_optional_project, :only => [:index, :changes]
|
||||
accept_key_auth :index, :changes
|
||||
|
||||
cache_sweeper :issue_sweeper, :only => [ :edit, :change_status, :destroy ]
|
||||
cache_sweeper :issue_sweeper, :only => [ :edit, :update, :destroy ]
|
||||
|
||||
helper :projects
|
||||
include ProjectsHelper
|
||||
|
@ -82,7 +82,8 @@ class IssuesController < ApplicationController
|
|||
def show
|
||||
@custom_values = @issue.custom_values.find(:all, :include => :custom_field, :order => "#{CustomField.table_name}.position")
|
||||
@journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
|
||||
@status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
|
||||
@status_options = @issue.new_statuses_allowed_to(User.current)
|
||||
@activities = Enumeration::get_values('ACTI')
|
||||
respond_to do |format|
|
||||
format.html { render :template => 'issues/show.rhtml' }
|
||||
format.pdf { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
|
||||
|
@ -115,47 +116,42 @@ class IssuesController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def add_note
|
||||
# Attributes that can be updated on workflow transition
|
||||
# TODO: make it configurable (at least per role)
|
||||
UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION)
|
||||
|
||||
def update
|
||||
@status_options = @issue.new_statuses_allowed_to(User.current)
|
||||
@activities = Enumeration::get_values('ACTI')
|
||||
journal = @issue.init_journal(User.current, params[:notes])
|
||||
attachments = attach_files(@issue, params[:attachments])
|
||||
attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
|
||||
if journal.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
||||
redirect_to :action => 'show', :id => @issue
|
||||
return
|
||||
# User can change issue attributes only if a workflow transition is allowed
|
||||
if !@status_options.empty? && params[:issue]
|
||||
attrs = params[:issue].dup
|
||||
attrs.delete_if {|k,v| !UPDATABLE_ATTRS_ON_TRANSITION.include?(k) }
|
||||
attrs.delete(:status_id) unless @status_options.detect {|s| s.id.to_s == attrs[:status_id].to_s}
|
||||
@issue.attributes = attrs
|
||||
end
|
||||
show
|
||||
end
|
||||
|
||||
def change_status
|
||||
@status_options = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
|
||||
@new_status = IssueStatus.find(params[:new_status_id])
|
||||
if params[:confirm]
|
||||
begin
|
||||
journal = @issue.init_journal(User.current, params[:notes])
|
||||
@issue.status = @new_status
|
||||
if @issue.update_attributes(params[:issue])
|
||||
attachments = attach_files(@issue, params[:attachments])
|
||||
attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
|
||||
# Log time
|
||||
if current_role.allowed_to?(:log_time)
|
||||
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
|
||||
@time_entry.attributes = params[:time_entry]
|
||||
@time_entry.save
|
||||
end
|
||||
|
||||
if request.post?
|
||||
attachments = attach_files(@issue, params[:attachments])
|
||||
attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)}
|
||||
if @issue.save
|
||||
# Log spend time
|
||||
if current_role.allowed_to?(:log_time)
|
||||
@time_entry = TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
|
||||
@time_entry.attributes = params[:time_entry]
|
||||
@time_entry.save
|
||||
end
|
||||
if !journal.new_record?
|
||||
# Only send notification if something was actually changed
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
|
||||
redirect_to :action => 'show', :id => @issue
|
||||
end
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
# Optimistic locking exception
|
||||
flash[:error] = l(:notice_locking_conflict)
|
||||
redirect_to(params[:back_to] || {:action => 'show', :id => @issue})
|
||||
end
|
||||
end
|
||||
@assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
|
||||
@activities = Enumeration::get_values('ACTI')
|
||||
end
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
# Optimistic locking exception
|
||||
flash.now[:error] = l(:notice_locking_conflict)
|
||||
end
|
||||
|
||||
def destroy
|
||||
|
@ -177,11 +173,11 @@ class IssuesController < ApplicationController
|
|||
def context_menu
|
||||
@priorities = Enumeration.get_values('IPRI').reverse
|
||||
@statuses = IssueStatus.find(:all, :order => 'position')
|
||||
@allowed_statuses = @issue.status.find_new_statuses_allowed_to(User.current.role_for_project(@project), @issue.tracker)
|
||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||
@assignables = @issue.assignable_users
|
||||
@assignables << @issue.assigned_to if @issue.assigned_to && !@assignables.include?(@issue.assigned_to)
|
||||
@can = {:edit => User.current.allowed_to?(:edit_issues, @project),
|
||||
:change_status => User.current.allowed_to?(:change_issue_status, @project),
|
||||
:assign => (@allowed_statuses.any? || User.current.allowed_to?(:edit_issues, @project)),
|
||||
:add => User.current.allowed_to?(:add_issues, @project),
|
||||
:move => User.current.allowed_to?(:move_issues, @project),
|
||||
:copy => (@project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)),
|
||||
|
|
|
@ -252,11 +252,9 @@ class ProjectsController < ApplicationController
|
|||
redirect_to :controller => 'issues', :action => 'index', :project_id => @project
|
||||
return
|
||||
end
|
||||
if current_role && User.current.allowed_to?(:change_issue_status, @project)
|
||||
# Find potential statuses the user could be allowed to switch issues to
|
||||
@available_statuses = Workflow.find(:all, :include => :new_status,
|
||||
:conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq
|
||||
end
|
||||
# Find potential statuses the user could be allowed to switch issues to
|
||||
@available_statuses = Workflow.find(:all, :include => :new_status,
|
||||
:conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq
|
||||
render :update do |page|
|
||||
page.hide 'query_form'
|
||||
page.replace_html 'bulk-edit', :partial => 'issues/bulk_edit_form'
|
||||
|
|
|
@ -180,6 +180,13 @@ class Issue < ActiveRecord::Base
|
|||
project.assignable_users
|
||||
end
|
||||
|
||||
# Returns an array of status that user is able to apply
|
||||
def new_statuses_allowed_to(user)
|
||||
statuses = status.find_new_statuses_allowed_to(user.role_for_project(project), tracker)
|
||||
statuses << status unless statuses.empty?
|
||||
statuses.uniq.sort
|
||||
end
|
||||
|
||||
# Returns the mail adresses of users that should be notified for the issue
|
||||
def recipients
|
||||
recipients = project.recipients
|
||||
|
|
|
@ -56,6 +56,10 @@ class IssueStatus < ActiveRecord::Base
|
|||
false
|
||||
end
|
||||
|
||||
def <=>(status)
|
||||
position <=> status.position
|
||||
end
|
||||
|
||||
def to_s; name end
|
||||
|
||||
private
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<fieldset class="box"><legend><%= l(:label_bulk_edit_selected_issues) %></legend>
|
||||
|
||||
<p>
|
||||
<% if @available_statuses %>
|
||||
<% if @available_statuses.any? %>
|
||||
<label><%= l(:field_status) %>:
|
||||
<%= select_tag('status_id', "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@available_statuses, :id, :name)) %></label>
|
||||
<% end %>
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
<% labelled_tabular_form_for(:issue, @issue, :url => {:action => 'update', :id => @issue}, :html => {:multipart => true}) do |f| %>
|
||||
|
||||
<div class="box">
|
||||
<% unless @status_options.empty? %>
|
||||
<%= f.hidden_field :lock_version %>
|
||||
<fieldset><legend><%= l(:label_change_properties) %></legend>
|
||||
<div class="splitcontentleft">
|
||||
<p><%= f.select :status_id, (@status_options.collect {|p| [p.name, p.id]}), :required => true %></p>
|
||||
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
|
||||
</div>
|
||||
<div class="splitcontentright">
|
||||
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
|
||||
<p><%= f.select :fixed_version_id, (@project.versions.sort.collect {|v| [v.name, v.id]}), { :include_blank => true } %></p>
|
||||
</div>
|
||||
</fieldset>
|
||||
<% end%>
|
||||
<% if authorize_for('timelog', 'edit') %>
|
||||
<fieldset><legend><%= l(:button_log_time) %></legend>
|
||||
<% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
|
||||
<div class="splitcontentleft">
|
||||
<p><%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %></p>
|
||||
</div>
|
||||
<div class="splitcontentright">
|
||||
<p><%= time_entry.text_field :comments, :size => 40 %></p>
|
||||
<p><%= time_entry.select :activity_id, (@activities.collect {|p| [p.name, p.id]}) %></p>
|
||||
</div>
|
||||
<% end %>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
<fieldset><legend><%= l(:field_notes) %></legend>
|
||||
<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
|
||||
<%= wikitoolbar_for 'notes' %>
|
||||
|
||||
<p id="attachments_p"><label><%=l(:label_attachment_new)%>
|
||||
<%= image_to_function "add.png", "addFileField();return false" %></label>
|
||||
<%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<%= submit_tag l(:button_submit) %>
|
||||
<% end %>
|
|
@ -1,38 +0,0 @@
|
|||
<h2><%=l(:label_issue)%> #<%= @issue.id %>: <%=h @issue.subject %></h2>
|
||||
|
||||
<%= error_messages_for 'issue' %>
|
||||
<% labelled_tabular_form_for(:issue, @issue, :url => {:action => 'change_status', :id => @issue}, :html => {:multipart => true}) do |f| %>
|
||||
|
||||
<%= hidden_field_tag 'confirm', 1 %>
|
||||
<%= hidden_field_tag 'new_status_id', @new_status.id %>
|
||||
<%= f.hidden_field :lock_version %>
|
||||
|
||||
<div class="box">
|
||||
<div class="splitcontentleft">
|
||||
<p><label><%=l(:label_issue_status_new)%></label> <%= @new_status.name %></p>
|
||||
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
|
||||
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
|
||||
<p><%= f.select :fixed_version_id, (@project.versions.sort.collect {|v| [v.name, v.id]}), { :include_blank => true } %></p>
|
||||
</div>
|
||||
<div class="splitcontentright">
|
||||
<% if authorize_for('timelog', 'edit') %>
|
||||
<% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
|
||||
<p><%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %></p>
|
||||
<p><%= time_entry.text_field :comments, :size => 40 %></p>
|
||||
<p><%= time_entry.select :activity_id, (@activities.collect {|p| [p.name, p.id]}) %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<div class="clear"></div>
|
||||
|
||||
<p><label for="notes"><%= l(:field_notes) %></label>
|
||||
<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %></p>
|
||||
|
||||
<p id="attachments_p"><label><%=l(:label_attachment_new)%>
|
||||
<%= image_to_function "add.png", "addFileField();return false" %></label>
|
||||
<%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p>
|
||||
</div>
|
||||
|
||||
<%= submit_tag l(:button_save) %>
|
||||
<% end %>
|
|
@ -6,8 +6,8 @@
|
|||
<a href="#" class="submenu" onclick="return false;"><%= l(:field_status) %></a>
|
||||
<ul>
|
||||
<% @statuses.each do |s| %>
|
||||
<li><%= context_menu_link s.name, {:controller => 'issues', :action => 'change_status', :id => @issue, :new_status_id => s},
|
||||
:selected => (s == @issue.status), :disabled => !(@can[:change_status] && @allowed_statuses.include?(s)) %></li>
|
||||
<li><%= context_menu_link s.name, {:controller => 'issues', :action => 'update', :id => @issue, :issue => {:status_id => s}},
|
||||
:selected => (s == @issue.status), :disabled => !(@allowed_statuses.include?(s)) %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -24,11 +24,11 @@
|
|||
<a href="#" class="submenu"><%= l(:field_assigned_to) %></a>
|
||||
<ul>
|
||||
<% @assignables.each do |u| %>
|
||||
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[assigned_to_id]' => u, :back_to => back_to}, :method => :post,
|
||||
:selected => (u == @issue.assigned_to), :disabled => !(@can[:edit] || @can[:change_status]) %></li>
|
||||
<li><%= context_menu_link u.name, {:controller => 'issues', :action => 'update', :id => @issue, :issue => {:assigned_to_id => u}, :back_to => back_to}, :method => :post,
|
||||
:selected => (u == @issue.assigned_to), :disabled => !@can[:assign] %></li>
|
||||
<% end %>
|
||||
<li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'edit', :id => @issue, 'issue[assigned_to_id]' => '', :back_to => back_to}, :method => :post,
|
||||
:selected => @issue.assigned_to.nil?, :disabled => !(@can[:edit] || @can[:change_status]) %></li>
|
||||
<li><%= context_menu_link l(:label_nobody), {:controller => 'issues', :action => 'update', :id => @issue, :issue => {:assigned_to_id => nil}, :back_to => back_to}, :method => :post,
|
||||
:selected => @issue.assigned_to.nil?, :disabled => !@can[:assign] %></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><%= context_menu_link l(:button_copy), {:controller => 'projects', :action => 'add_issue', :id => @project, :copy_from => @issue},
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="contextual">
|
||||
<%= show_and_goto_link(l(:label_add_note), 'add-note', :class => 'icon icon-note') if authorize_for('issues', 'add_note') %>
|
||||
<%= show_and_goto_link(l(:button_update), 'update', :class => 'icon icon-note') if authorize_for('issues', 'update') %>
|
||||
<%= link_to_if_authorized l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, :class => 'icon icon-edit', :accesskey => accesskey(:edit) %>
|
||||
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
|
||||
<%= watcher_tag(@issue, User.current) %>
|
||||
|
@ -81,16 +81,6 @@ end %>
|
|||
|
||||
</div>
|
||||
|
||||
<% if authorize_for('issues', 'change_status') and @status_options and !@status_options.empty? %>
|
||||
<% form_tag({:controller => 'issues', :action => 'change_status', :id => @issue}) do %>
|
||||
<p><%=l(:label_change_status)%> :
|
||||
<select name="new_status_id">
|
||||
<%= options_from_collection_for_select @status_options, "id", "name", @issue.status_id %>
|
||||
</select>
|
||||
<%= submit_tag l(:button_change) %></p>
|
||||
<% end %>
|
||||
<% end %>
|
||||
|
||||
<% if @journals.any? %>
|
||||
<div id="history">
|
||||
<h3><%=l(:label_history)%></h3>
|
||||
|
@ -98,18 +88,12 @@ end %>
|
|||
</div>
|
||||
<% end %>
|
||||
|
||||
<% if authorize_for('issues', 'add_note') %>
|
||||
<a name="add-note-anchor"></a>
|
||||
<div id="add-note" class="box" style="display:none;">
|
||||
<h3><%= l(:label_add_note) %></h3>
|
||||
<% form_tag({:controller => 'issues', :action => 'add_note', :id => @issue}, :class => "tabular", :multipart => true) do %>
|
||||
<p><label for="notes"><%=l(:field_notes)%></label>
|
||||
<%= text_area_tag 'notes', '', :cols => 60, :rows => 10, :class => 'wiki-edit' %></p>
|
||||
<%= wikitoolbar_for 'notes' %>
|
||||
<%= render :partial => 'attachments/form' %>
|
||||
<%= submit_tag l(:button_add) %>
|
||||
<%= toggle_link l(:button_cancel), 'add-note' %>
|
||||
<% end %>
|
||||
<% if authorize_for('issues', 'update') %>
|
||||
<a name="update-anchor"></a>
|
||||
<div id="update" style="display:none;">
|
||||
<h3><%= l(:button_update) %></h3>
|
||||
<%= render :partial => 'update' %>
|
||||
<%= toggle_link l(:button_cancel), 'update' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<h2><%= @issue.tracker.name %> #<%= @issue.id %>: <%=h @issue.subject %></h2>
|
||||
|
||||
<%= error_messages_for 'issue' %>
|
||||
<%= render :partial => 'update' %>
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -462,6 +462,7 @@ label_registration_manual_activation: manual account activation
|
|||
label_registration_automatic_activation: automatic account activation
|
||||
label_display_per_page: 'Per page: %s'
|
||||
label_age: Age
|
||||
label_change_properties: Change properties
|
||||
|
||||
button_login: Login
|
||||
button_submit: Submit
|
||||
|
@ -498,6 +499,7 @@ button_rename: Rename
|
|||
button_change_password: Change password
|
||||
button_copy: Copy
|
||||
button_annotate: Annotate
|
||||
button_update: Update
|
||||
|
||||
status_active: active
|
||||
status_registered: registered
|
||||
|
|
|
@ -560,3 +560,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -462,6 +462,7 @@ label_registration_manual_activation: activation manuelle du compte
|
|||
label_registration_automatic_activation: activation automatique du compte
|
||||
label_display_per_page: 'Par page: %s'
|
||||
label_age: Age
|
||||
label_change_properties: Changer les propriétés
|
||||
|
||||
button_login: Connexion
|
||||
button_submit: Soumettre
|
||||
|
@ -498,6 +499,7 @@ button_rename: Renommer
|
|||
button_change_password: Changer de mot de passe
|
||||
button_copy: Copier
|
||||
button_annotate: Annoter
|
||||
button_update: Mettre à jour
|
||||
|
||||
status_active: actif
|
||||
status_registered: enregistré
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -558,3 +558,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -558,3 +558,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -558,3 +558,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -558,3 +558,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -557,3 +557,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -560,3 +560,5 @@ notice_default_data_loaded: Default configuration successfully loaded.
|
|||
text_load_default_configuration: Load the default configuration
|
||||
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
|
||||
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
|
||||
button_update: Update
|
||||
label_change_properties: Change properties
|
||||
|
|
|
@ -32,10 +32,9 @@ Redmine::AccessControl.map do |map|
|
|||
:reports => :issue_report}, :public => true
|
||||
map.permission :add_issues, {:projects => :add_issue}
|
||||
map.permission :edit_issues, {:projects => :bulk_edit_issues,
|
||||
:issues => [:edit, :destroy_attachment]}
|
||||
:issues => [:edit, :update, :destroy_attachment]}
|
||||
map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}
|
||||
map.permission :add_issue_notes, {:issues => :add_note}
|
||||
map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin
|
||||
map.permission :add_issue_notes, {:issues => :update}
|
||||
map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin
|
||||
map.permission :delete_issues, {:issues => :destroy}, :require => :member
|
||||
# Queries
|
||||
|
|
|
@ -53,7 +53,6 @@ module Redmine
|
|||
:edit_issues,
|
||||
:manage_issue_relations,
|
||||
:add_issue_notes,
|
||||
:change_issue_status,
|
||||
:save_queries,
|
||||
:view_gantt,
|
||||
:view_calendar,
|
||||
|
@ -74,7 +73,6 @@ module Redmine
|
|||
:position => 3,
|
||||
:permissions => [:add_issues,
|
||||
:add_issue_notes,
|
||||
:change_issue_status,
|
||||
:save_queries,
|
||||
:view_gantt,
|
||||
:view_calendar,
|
||||
|
@ -90,7 +88,6 @@ module Redmine
|
|||
|
||||
Role.non_member.update_attribute :permissions, [:add_issues,
|
||||
:add_issue_notes,
|
||||
:change_issue_status,
|
||||
:save_queries,
|
||||
:view_gantt,
|
||||
:view_calendar,
|
||||
|
|
|
@ -31,3 +31,12 @@ enumerations_008:
|
|||
name: Immediate
|
||||
id: 8
|
||||
opt: IPRI
|
||||
enumerations_009:
|
||||
name: Design
|
||||
id: 9
|
||||
opt: ACTI
|
||||
enumerations_010:
|
||||
name: Development
|
||||
id: 10
|
||||
opt: ACTI
|
||||
|
|
@ -9,7 +9,6 @@ roles_004:
|
|||
- :edit_issues
|
||||
- :manage_issue_relations
|
||||
- :add_issue_notes
|
||||
- :change_issue_status
|
||||
- :move_issues
|
||||
- :save_queries
|
||||
- :view_gantt
|
||||
|
@ -34,6 +33,7 @@ roles_005:
|
|||
builtin: 2
|
||||
permissions: |
|
||||
---
|
||||
- :add_issue_notes
|
||||
- :view_gantt
|
||||
- :view_calendar
|
||||
- :view_time_entries
|
||||
|
@ -58,7 +58,6 @@ roles_001:
|
|||
- :edit_issues
|
||||
- :manage_issue_relations
|
||||
- :add_issue_notes
|
||||
- :change_issue_status
|
||||
- :move_issues
|
||||
- :delete_issues
|
||||
- :manage_public_queries
|
||||
|
@ -99,7 +98,6 @@ roles_002:
|
|||
- :edit_issues
|
||||
- :manage_issue_relations
|
||||
- :add_issue_notes
|
||||
- :change_issue_status
|
||||
- :move_issues
|
||||
- :delete_issues
|
||||
- :manage_public_queries
|
||||
|
@ -137,7 +135,6 @@ roles_003:
|
|||
- :edit_issues
|
||||
- :manage_issue_relations
|
||||
- :add_issue_notes
|
||||
- :change_issue_status
|
||||
- :move_issues
|
||||
- :delete_issues
|
||||
- :manage_public_queries
|
||||
|
|
|
@ -14,6 +14,7 @@ users_004:
|
|||
auth_source_id:
|
||||
mail_notification: true
|
||||
login: rhill
|
||||
type: User
|
||||
users_001:
|
||||
created_on: 2006-07-19 19:12:21 +02:00
|
||||
status: 1
|
||||
|
@ -29,6 +30,7 @@ users_001:
|
|||
auth_source_id:
|
||||
mail_notification: true
|
||||
login: admin
|
||||
type: User
|
||||
users_002:
|
||||
created_on: 2006-07-19 19:32:09 +02:00
|
||||
status: 1
|
||||
|
@ -44,6 +46,7 @@ users_002:
|
|||
auth_source_id:
|
||||
mail_notification: true
|
||||
login: jsmith
|
||||
type: User
|
||||
users_003:
|
||||
created_on: 2006-07-19 19:33:19 +02:00
|
||||
status: 1
|
||||
|
@ -59,6 +62,7 @@ users_003:
|
|||
auth_source_id:
|
||||
mail_notification: true
|
||||
login: dlopper
|
||||
type: User
|
||||
users_005:
|
||||
id: 5
|
||||
created_on: 2006-07-19 19:33:19 +02:00
|
||||
|
@ -75,3 +79,22 @@ users_005:
|
|||
auth_source_id:
|
||||
mail_notification: true
|
||||
login: dlopper2
|
||||
type: User
|
||||
users_006:
|
||||
id: 6
|
||||
created_on: 2006-07-19 19:33:19 +02:00
|
||||
status: 1
|
||||
last_login_on:
|
||||
language: ''
|
||||
hashed_password: 1
|
||||
updated_on: 2006-07-19 19:33:19 +02:00
|
||||
admin: false
|
||||
mail: ''
|
||||
lastname: Anonymous
|
||||
firstname: ''
|
||||
auth_source_id:
|
||||
mail_notification: false
|
||||
login: ''
|
||||
type: AnonymousUser
|
||||
|
||||
|
|
@ -32,7 +32,8 @@ class IssuesControllerTest < Test::Unit::TestCase
|
|||
:issue_categories,
|
||||
:enabled_modules,
|
||||
:enumerations,
|
||||
:attachments
|
||||
:attachments,
|
||||
:workflows
|
||||
|
||||
def setup
|
||||
@controller = IssuesController.new
|
||||
|
@ -94,13 +95,37 @@ class IssuesControllerTest < Test::Unit::TestCase
|
|||
assert_equal 'application/atom+xml', @response.content_type
|
||||
end
|
||||
|
||||
def test_show
|
||||
def test_show_by_anonymous
|
||||
get :show, :id => 1
|
||||
assert_response :success
|
||||
assert_template 'show.rhtml'
|
||||
assert_not_nil assigns(:issue)
|
||||
assert_equal Issue.find(1), assigns(:issue)
|
||||
|
||||
# anonymous role is allowed to add a note
|
||||
assert_tag :tag => 'form',
|
||||
:descendant => { :tag => 'fieldset',
|
||||
:child => { :tag => 'legend',
|
||||
:content => /Notes/ } }
|
||||
end
|
||||
|
||||
def test_show_by_manager
|
||||
@request.session[:user_id] = 2
|
||||
get :show, :id => 1
|
||||
assert_response :success
|
||||
|
||||
assert_tag :tag => 'form',
|
||||
:descendant => { :tag => 'fieldset',
|
||||
:child => { :tag => 'legend',
|
||||
:content => /Change properties/ } },
|
||||
:descendant => { :tag => 'fieldset',
|
||||
:child => { :tag => 'legend',
|
||||
:content => /Log time/ } },
|
||||
:descendant => { :tag => 'fieldset',
|
||||
:child => { :tag => 'legend',
|
||||
:content => /Notes/ } }
|
||||
end
|
||||
|
||||
def test_get_edit
|
||||
@request.session[:user_id] = 2
|
||||
get :edit, :id => 1
|
||||
|
@ -129,21 +154,100 @@ class IssuesControllerTest < Test::Unit::TestCase
|
|||
assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}")
|
||||
end
|
||||
|
||||
def test_post_change_status
|
||||
def test_get_update
|
||||
@request.session[:user_id] = 2
|
||||
get :update, :id => 1
|
||||
assert_response :success
|
||||
assert_template 'update'
|
||||
end
|
||||
|
||||
def test_update_with_status_and_assignee_change
|
||||
issue = Issue.find(1)
|
||||
assert_equal 1, issue.status_id
|
||||
@request.session[:user_id] = 2
|
||||
post :change_status, :id => 1,
|
||||
:new_status_id => 2,
|
||||
:issue => { :assigned_to_id => 3 },
|
||||
:notes => 'Assigned to dlopper',
|
||||
:confirm => 1
|
||||
post :update,
|
||||
:id => 1,
|
||||
:issue => { :status_id => 2, :assigned_to_id => 3 },
|
||||
:notes => 'Assigned to dlopper'
|
||||
assert_redirected_to 'issues/show/1'
|
||||
issue.reload
|
||||
assert_equal 2, issue.status_id
|
||||
j = issue.journals.find(:first, :order => 'created_on DESC')
|
||||
j = issue.journals.find(:first, :order => 'id DESC')
|
||||
assert_equal 'Assigned to dlopper', j.notes
|
||||
assert_equal 2, j.details.size
|
||||
|
||||
mail = ActionMailer::Base.deliveries.last
|
||||
assert mail.body.include?("Status changed from New to Assigned")
|
||||
end
|
||||
|
||||
def test_update_with_note_only
|
||||
notes = 'Note added by IssuesControllerTest#test_update_with_note_only'
|
||||
# anonymous user
|
||||
post :update,
|
||||
:id => 1,
|
||||
:notes => notes
|
||||
assert_redirected_to 'issues/show/1'
|
||||
j = Issue.find(1).journals.find(:first, :order => 'id DESC')
|
||||
assert_equal notes, j.notes
|
||||
assert_equal 0, j.details.size
|
||||
assert_equal User.anonymous, j.user
|
||||
|
||||
mail = ActionMailer::Base.deliveries.last
|
||||
assert mail.body.include?(notes)
|
||||
end
|
||||
|
||||
def test_update_with_note_and_spent_time
|
||||
@request.session[:user_id] = 2
|
||||
spent_hours_before = Issue.find(1).spent_hours
|
||||
post :update,
|
||||
:id => 1,
|
||||
:notes => '2.5 hours added',
|
||||
:time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.get_values('ACTI').first }
|
||||
assert_redirected_to 'issues/show/1'
|
||||
|
||||
issue = Issue.find(1)
|
||||
|
||||
j = issue.journals.find(:first, :order => 'id DESC')
|
||||
assert_equal '2.5 hours added', j.notes
|
||||
assert_equal 0, j.details.size
|
||||
|
||||
t = issue.time_entries.find(:first, :order => 'id DESC')
|
||||
assert_not_nil t
|
||||
assert_equal 2.5, t.hours
|
||||
assert_equal spent_hours_before + 2.5, issue.spent_hours
|
||||
end
|
||||
|
||||
def test_update_with_attachment_only
|
||||
# anonymous user
|
||||
post :update,
|
||||
:id => 1,
|
||||
:notes => '',
|
||||
:attachments => [ test_uploaded_file('testfile.txt', 'text/plain') ]
|
||||
assert_redirected_to 'issues/show/1'
|
||||
j = Issue.find(1).journals.find(:first, :order => 'id DESC')
|
||||
assert j.notes.blank?
|
||||
assert_equal 1, j.details.size
|
||||
assert_equal 'testfile.txt', j.details.first.value
|
||||
assert_equal User.anonymous, j.user
|
||||
|
||||
mail = ActionMailer::Base.deliveries.last
|
||||
assert mail.body.include?('testfile.txt')
|
||||
end
|
||||
|
||||
def test_update_with_no_change
|
||||
issue = Issue.find(1)
|
||||
issue.journals.clear
|
||||
ActionMailer::Base.deliveries.clear
|
||||
|
||||
post :update,
|
||||
:id => 1,
|
||||
:notes => ''
|
||||
assert_redirected_to 'issues/show/1'
|
||||
|
||||
issue.reload
|
||||
assert issue.journals.empty?
|
||||
# No email should be sent
|
||||
assert ActionMailer::Base.deliveries.empty?
|
||||
end
|
||||
|
||||
def test_context_menu
|
||||
|
|
|
@ -38,7 +38,9 @@ class IssuesTest < ActionController::IntegrationTest
|
|||
def test_issue_attachements
|
||||
log_user('jsmith', 'jsmith')
|
||||
|
||||
post "issues/add_note/1", { :notes => 'Some notes', 'attachments[]' => ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/testfile.txt', 'text/plain') }
|
||||
post 'issues/update/1',
|
||||
:notes => 'Some notes',
|
||||
:attachments => ([] << ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + '/files/testfile.txt', 'text/plain'))
|
||||
assert_redirected_to "issues/show/1"
|
||||
|
||||
# make sure attachment was saved
|
||||
|
|
|
@ -53,6 +53,10 @@ class Test::Unit::TestCase
|
|||
assert_redirected_to "my/page"
|
||||
assert_equal login, User.find(session[:user_id]).login
|
||||
end
|
||||
|
||||
def test_uploaded_file(name, mime)
|
||||
ActionController::TestUploadedFile.new(Test::Unit::TestCase.fixture_path + "/files/#{name}", mime)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
@ -70,4 +74,4 @@ class String
|
|||
def read
|
||||
self.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -155,6 +155,27 @@ module ActiveRecord #:nodoc:
|
|||
# end
|
||||
# end
|
||||
|
||||
class Errors
|
||||
include GLoc
|
||||
|
||||
def full_messages
|
||||
full_messages = []
|
||||
|
||||
@errors.each_key do |attr|
|
||||
@errors[attr].each do |msg|
|
||||
next if msg.nil?
|
||||
|
||||
if attr == "base"
|
||||
full_messages << (msg.is_a?(Symbol) ? l(msg) : msg)
|
||||
else
|
||||
full_messages << @base.class.human_attribute_name(attr) + " " + (msg.is_a?(Symbol) ? l(msg) : msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
full_messages
|
||||
end
|
||||
end
|
||||
|
||||
module Validations #:nodoc:
|
||||
module ClassMethods
|
||||
# The default Rails version of this function creates an error message and then
|
||||
|
|
Loading…
Reference in New Issue