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
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") }
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
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)),
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'
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
false
end
+ def <=>(status)
+ position <=> status.position
+ end
+
def to_s; name end
private
<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 %>
--- /dev/null
+<% 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 %>
+++ /dev/null
-<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 %>
<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>
<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},
<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) %>
</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>
</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 %>
--- /dev/null
+<h2><%= @issue.tracker.name %> #<%= @issue.id %>: <%=h @issue.subject %></h2>
+
+<%= error_messages_for 'issue' %>
+<%= render :partial => 'update' %>
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
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
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
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
button_change_password: Change password
button_copy: Copy
button_annotate: Annotate
+button_update: Update
status_active: active
status_registered: registered
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
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
button_change_password: Changer de mot de passe
button_copy: Copier
button_annotate: Annoter
+button_update: Mettre à jour
status_active: actif
status_registered: enregistré
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
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
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
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
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
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
text_load_default_configuration: Load the default configuration\r
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."\r
error_can_t_load_default_data: "Default configuration could not be loaded: %s"\r
+button_update: Update\r
+label_change_properties: Change properties\r
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
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
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
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
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
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
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
: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
:edit_issues,
:manage_issue_relations,
:add_issue_notes,
- :change_issue_status,
:save_queries,
:view_gantt,
:view_calendar,
:position => 3,
:permissions => [:add_issues,
:add_issue_notes,
- :change_issue_status,
:save_queries,
:view_gantt,
:view_calendar,
Role.non_member.update_attribute :permissions, [:add_issues,
:add_issue_notes,
- :change_issue_status,
:save_queries,
:view_gantt,
:view_calendar,
name: Immediate\r
id: 8\r
opt: IPRI\r
+enumerations_009: \r
+ name: Design\r
+ id: 9\r
+ opt: ACTI\r
+enumerations_010: \r
+ name: Development\r
+ id: 10\r
+ opt: ACTI\r
+
\ No newline at end of file
- :edit_issues\r
- :manage_issue_relations\r
- :add_issue_notes\r
- - :change_issue_status\r
- :move_issues\r
- :save_queries\r
- :view_gantt\r
builtin: 2\r
permissions: |\r
--- \r
+ - :add_issue_notes\r
- :view_gantt\r
- :view_calendar\r
- :view_time_entries\r
- :edit_issues\r
- :manage_issue_relations\r
- :add_issue_notes\r
- - :change_issue_status\r
- :move_issues\r
- :delete_issues\r
- :manage_public_queries\r
- :edit_issues\r
- :manage_issue_relations\r
- :add_issue_notes\r
- - :change_issue_status\r
- :move_issues\r
- :delete_issues\r
- :manage_public_queries\r
- :edit_issues\r
- :manage_issue_relations\r
- :add_issue_notes\r
- - :change_issue_status\r
- :move_issues\r
- :delete_issues\r
- :manage_public_queries\r
auth_source_id: \r
mail_notification: true\r
login: rhill\r
+ type: User\r
users_001: \r
created_on: 2006-07-19 19:12:21 +02:00\r
status: 1\r
auth_source_id: \r
mail_notification: true\r
login: admin\r
+ type: User\r
users_002: \r
created_on: 2006-07-19 19:32:09 +02:00\r
status: 1\r
auth_source_id: \r
mail_notification: true\r
login: jsmith\r
+ type: User\r
users_003: \r
created_on: 2006-07-19 19:33:19 +02:00\r
status: 1\r
auth_source_id: \r
mail_notification: true\r
login: dlopper\r
+ type: User\r
users_005: \r
id: 5\r
created_on: 2006-07-19 19:33:19 +02:00\r
auth_source_id: \r
mail_notification: true\r
login: dlopper2\r
+ type: User\r
+users_006: \r
+ id: 6\r
+ created_on: 2006-07-19 19:33:19 +02:00\r
+ status: 1\r
+ last_login_on: \r
+ language: ''\r
+ hashed_password: 1\r
+ updated_on: 2006-07-19 19:33:19 +02:00\r
+ admin: false\r
+ mail: ''\r
+ lastname: Anonymous\r
+ firstname: ''\r
+ auth_source_id: \r
+ mail_notification: false\r
+ login: ''\r
+ type: AnonymousUser\r
+\r
+
\ No newline at end of file
:issue_categories,
:enabled_modules,
:enumerations,
- :attachments
+ :attachments,
+ :workflows
def setup
@controller = IssuesController.new
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
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
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
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
def read
self.to_s
end
-end
\ No newline at end of file
+end
# end\r
# end\r
\r
+ class Errors\r
+ include GLoc\r
+ \r
+ def full_messages\r
+ full_messages = []\r
+\r
+ @errors.each_key do |attr|\r
+ @errors[attr].each do |msg|\r
+ next if msg.nil?\r
+\r
+ if attr == "base"\r
+ full_messages << (msg.is_a?(Symbol) ? l(msg) : msg)\r
+ else\r
+ full_messages << @base.class.human_attribute_name(attr) + " " + (msg.is_a?(Symbol) ? l(msg) : msg)\r
+ end\r
+ end\r
+ end\r
+ full_messages\r
+ end\r
+ end\r
+ \r
module Validations #:nodoc:\r
module ClassMethods\r
# The default Rails version of this function creates an error message and then\r