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:
Jean-Philippe Lang 2008-01-06 17:06:14 +00:00
parent 4a729036bf
commit 976a31e941
39 changed files with 326 additions and 133 deletions

View File

@ -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
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
end
show
end
# 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 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
def update
@status_options = @issue.new_statuses_allowed_to(User.current)
@activities = Enumeration::get_values('ACTI')
journal = @issue.init_journal(User.current, params[:notes])
@issue.status = @new_status
if @issue.update_attributes(params[:issue])
# 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
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)}
# Log time
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 = 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
redirect_to(params[:back_to] || {:action => 'show', :id => @issue})
end
end
rescue ActiveRecord::StaleObjectError
# Optimistic locking exception
flash[:error] = l(:notice_locking_conflict)
end
end
@assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
@activities = Enumeration::get_values('ACTI')
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)),

View File

@ -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
render :update do |page|
page.hide 'query_form'
page.replace_html 'bulk-edit', :partial => 'issues/bulk_edit_form'

View File

@ -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

View File

@ -56,6 +56,10 @@ class IssueStatus < ActiveRecord::Base
false
end
def <=>(status)
position <=> status.position
end
def to_s; name end
private

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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 %>

View File

@ -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},

View File

@ -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 %>

View File

@ -0,0 +1,4 @@
<h2><%= @issue.tracker.name %> #<%= @issue.id %>: <%=h @issue.subject %></h2>
<%= error_messages_for 'issue' %>
<%= render :partial => 'update' %>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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é

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -32,7 +32,8 @@ class IssuesControllerTest < Test::Unit::TestCase
:issue_categories,
:enabled_modules,
:enumerations,
:attachments
:attachments,
:workflows
def setup
@controller = IssuesController.new
@ -94,11 +95,35 @@ 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
@ -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

View File

@ -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

View File

@ -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

View File

@ -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