Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7578e485a5 | ||
|
|
a35b81b9fa | ||
|
|
fd450fd2da | ||
|
|
2c0ba78f70 | ||
|
|
f0f01d370e | ||
|
|
4c330a1241 | ||
|
|
baa4ebd05f | ||
|
|
59f14478ed | ||
|
|
8fefb7c05b | ||
|
|
1feb373c89 | ||
|
|
32fd503cbb | ||
|
|
cf31aeaf81 | ||
|
|
83ea66fd2c | ||
|
|
ef2c5cab2d | ||
|
|
dee6f6b138 | ||
|
|
a4c0c18e3d | ||
|
|
4c82fbb6f8 | ||
|
|
68ded50edc | ||
|
|
72ecb80dc7 | ||
|
|
86ee285eb4 | ||
|
|
c229ea6386 | ||
|
|
687fca170e | ||
|
|
26564b06f7 | ||
|
|
34016c38bd | ||
|
|
15ff361894 | ||
|
|
b45b5f4322 | ||
|
|
8addbc537a | ||
|
|
87eeacba80 | ||
|
|
a7250c41e2 | ||
|
|
7c45396d92 | ||
|
|
c1f98c835c |
@@ -2,7 +2,7 @@ source :rubygems
|
|||||||
|
|
||||||
gem "rails", "2.3.14"
|
gem "rails", "2.3.14"
|
||||||
gem "i18n", "~> 0.4.2"
|
gem "i18n", "~> 0.4.2"
|
||||||
gem "coderay", "~> 1.0.0"
|
gem "coderay", "~> 1.0.6"
|
||||||
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
|
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
|
||||||
gem "tzinfo", "~> 0.3.31"
|
gem "tzinfo", "~> 0.3.31"
|
||||||
|
|
||||||
@@ -16,18 +16,20 @@ group :openid do
|
|||||||
gem "ruby-openid", "~> 2.1.4", :require => "openid"
|
gem "ruby-openid", "~> 2.1.4", :require => "openid"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Optional gem for exporting the gantt to a PNG file
|
# Optional gem for exporting the gantt to a PNG file, not supported with jruby
|
||||||
group :rmagick do
|
platforms :mri, :mingw do
|
||||||
# RMagick 2 supports ruby 1.9
|
group :rmagick do
|
||||||
# RMagick 1 would be fine for ruby 1.8 but Bundler does not support
|
# RMagick 2 supports ruby 1.9
|
||||||
# different requirements for the same gem on different platforms
|
# RMagick 1 would be fine for ruby 1.8 but Bundler does not support
|
||||||
gem "rmagick", ">= 2.0.0"
|
# different requirements for the same gem on different platforms
|
||||||
|
gem "rmagick", ">= 2.0.0"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Database gems
|
# Database gems
|
||||||
platforms :mri, :mingw do
|
platforms :mri, :mingw do
|
||||||
group :postgresql do
|
group :postgresql do
|
||||||
gem "pg", "~> 0.9.0"
|
gem "pg", ">= 0.11.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
group :sqlite do
|
group :sqlite do
|
||||||
@@ -73,6 +75,11 @@ group :test do
|
|||||||
gem "mocha"
|
gem "mocha"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if File.exists?('Gemfile.local')
|
||||||
|
puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v`
|
||||||
|
instance_eval File.read('Gemfile.local')
|
||||||
|
end
|
||||||
|
|
||||||
# Load plugins' Gemfiles
|
# Load plugins' Gemfiles
|
||||||
Dir.glob File.expand_path("../vendor/plugins/*/Gemfile", __FILE__) do |file|
|
Dir.glob File.expand_path("../vendor/plugins/*/Gemfile", __FILE__) do |file|
|
||||||
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
||||||
|
|||||||
@@ -75,9 +75,7 @@ class AdminController < ApplicationController
|
|||||||
def info
|
def info
|
||||||
@db_adapter_name = ActiveRecord::Base.connection.adapter_name
|
@db_adapter_name = ActiveRecord::Base.connection.adapter_name
|
||||||
@checklist = [
|
@checklist = [
|
||||||
[:text_default_administrator_account_changed,
|
[:text_default_administrator_account_changed, User.default_admin_account_changed?],
|
||||||
User.find(:first,
|
|
||||||
:conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?],
|
|
||||||
[:text_file_repository_writable, File.writable?(Attachment.storage_path)],
|
[:text_file_repository_writable, File.writable?(Attachment.storage_path)],
|
||||||
[:text_plugin_assets_writable, File.writable?(Redmine::Plugin.public_directory)],
|
[:text_plugin_assets_writable, File.writable?(Redmine::Plugin.public_directory)],
|
||||||
[:text_rmagick_available, Object.const_defined?(:Magick)]
|
[:text_rmagick_available, Object.const_defined?(:Magick)]
|
||||||
|
|||||||
@@ -364,18 +364,6 @@ class ApplicationController < ActionController::Base
|
|||||||
:content_type => 'application/atom+xml'
|
:content_type => 'application/atom+xml'
|
||||||
end
|
end
|
||||||
|
|
||||||
# TODO: remove in Redmine 1.4
|
|
||||||
def self.accept_key_auth(*actions)
|
|
||||||
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead."
|
|
||||||
accept_rss_auth(*actions)
|
|
||||||
end
|
|
||||||
|
|
||||||
# TODO: remove in Redmine 1.4
|
|
||||||
def accept_key_auth_actions
|
|
||||||
ActiveSupport::Deprecation.warn "ApplicationController.accept_key_auth_actions is deprecated and will be removed in Redmine 1.4. Use accept_rss_auth (or accept_api_auth) instead."
|
|
||||||
self.class.accept_rss_auth
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.accept_rss_auth(*actions)
|
def self.accept_rss_auth(*actions)
|
||||||
if actions.any?
|
if actions.any?
|
||||||
write_inheritable_attribute('accept_rss_auth_actions', actions)
|
write_inheritable_attribute('accept_rss_auth_actions', actions)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class BoardsController < ApplicationController
|
|||||||
:include => [:author, {:last_reply => :author}],
|
:include => [:author, {:last_reply => :author}],
|
||||||
:limit => @topic_pages.items_per_page,
|
:limit => @topic_pages.items_per_page,
|
||||||
:offset => @topic_pages.current.offset
|
:offset => @topic_pages.current.offset
|
||||||
@message = Message.new
|
@message = Message.new(:board => @board)
|
||||||
render :action => 'show', :layout => !request.xhr?
|
render :action => 'show', :layout => !request.xhr?
|
||||||
}
|
}
|
||||||
format.atom {
|
format.atom {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class IssueRelationsController < ApplicationController
|
|||||||
def create
|
def create
|
||||||
@relation = IssueRelation.new(params[:relation])
|
@relation = IssueRelation.new(params[:relation])
|
||||||
@relation.issue_from = @issue
|
@relation.issue_from = @issue
|
||||||
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
|
if params[:relation] && m = params[:relation][:issue_to_id].to_s.strip.match(/^#?(\d+)$/)
|
||||||
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
|
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
|
||||||
end
|
end
|
||||||
saved = @relation.save
|
saved = @relation.save
|
||||||
|
|||||||
@@ -225,12 +225,19 @@ class IssuesController < ApplicationController
|
|||||||
end
|
end
|
||||||
target_projects ||= @projects
|
target_projects ||= @projects
|
||||||
|
|
||||||
@available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
|
if @copy
|
||||||
|
@available_statuses = [IssueStatus.default]
|
||||||
|
else
|
||||||
|
@available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&)
|
||||||
|
end
|
||||||
@custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&)
|
@custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&)
|
||||||
@assignables = target_projects.map(&:assignable_users).reduce(:&)
|
@assignables = target_projects.map(&:assignable_users).reduce(:&)
|
||||||
@trackers = target_projects.map(&:trackers).reduce(:&)
|
@trackers = target_projects.map(&:trackers).reduce(:&)
|
||||||
@versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
|
@versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&)
|
||||||
@categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
|
@categories = target_projects.map {|p| p.issue_categories}.reduce(:&)
|
||||||
|
if @copy
|
||||||
|
@attachments_present = @issues.detect {|i| i.attachments.any?}.present?
|
||||||
|
end
|
||||||
|
|
||||||
@safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
|
@safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&)
|
||||||
render :layout => false if request.xhr?
|
render :layout => false if request.xhr?
|
||||||
@@ -246,7 +253,7 @@ class IssuesController < ApplicationController
|
|||||||
@issues.each do |issue|
|
@issues.each do |issue|
|
||||||
issue.reload
|
issue.reload
|
||||||
if @copy
|
if @copy
|
||||||
issue = issue.copy
|
issue = issue.copy({}, :attachments => params[:copy_attachments].present?)
|
||||||
end
|
end
|
||||||
journal = issue.init_journal(User.current, params[:notes])
|
journal = issue.init_journal(User.current, params[:notes])
|
||||||
issue.safe_attributes = attributes
|
issue.safe_attributes = attributes
|
||||||
@@ -348,8 +355,6 @@ private
|
|||||||
# from the params
|
# from the params
|
||||||
# TODO: Refactor, not everything in here is needed by #edit
|
# TODO: Refactor, not everything in here is needed by #edit
|
||||||
def update_issue_from_params
|
def update_issue_from_params
|
||||||
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
|
||||||
@priorities = IssuePriority.active
|
|
||||||
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
||||||
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
|
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
|
||||||
@time_entry.attributes = params[:time_entry]
|
@time_entry.attributes = params[:time_entry]
|
||||||
@@ -371,6 +376,8 @@ private
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
@issue.safe_attributes = issue_attributes
|
@issue.safe_attributes = issue_attributes
|
||||||
|
@priorities = IssuePriority.active
|
||||||
|
@allowed_statuses = @issue.new_statuses_allowed_to(User.current)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -420,7 +427,16 @@ private
|
|||||||
def parse_params_for_bulk_issue_attributes(params)
|
def parse_params_for_bulk_issue_attributes(params)
|
||||||
attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
|
attributes = (params[:issue] || {}).reject {|k,v| v.blank?}
|
||||||
attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
|
attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'}
|
||||||
attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values]
|
if custom = attributes[:custom_field_values]
|
||||||
|
custom.reject! {|k,v| v.blank?}
|
||||||
|
custom.keys.each do |k|
|
||||||
|
if custom[k].is_a?(Array)
|
||||||
|
custom[k] << '' if custom[k].delete('__none__')
|
||||||
|
else
|
||||||
|
custom[k] = '' if custom[k] == '__none__'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
attributes
|
attributes
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ module CustomFieldsHelper
|
|||||||
when "list"
|
when "list"
|
||||||
options = []
|
options = []
|
||||||
options << [l(:label_no_change_option), ''] unless custom_field.multiple?
|
options << [l(:label_no_change_option), ''] unless custom_field.multiple?
|
||||||
|
options << [l(:label_none), '__none__'] unless custom_field.is_required?
|
||||||
options += custom_field.possible_values_options(projects)
|
options += custom_field.possible_values_options(projects)
|
||||||
select_tag(field_name, options_for_select(options),
|
select_tag(field_name, options_for_select(options),
|
||||||
:id => field_id, :multiple => custom_field.multiple?)
|
:id => field_id, :multiple => custom_field.multiple?)
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ module IssuesHelper
|
|||||||
cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
|
cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id}
|
||||||
show_value(cv)
|
show_value(cv)
|
||||||
else
|
else
|
||||||
value = issue.send(column.name)
|
value = column.value(issue)
|
||||||
if value.is_a?(Date)
|
if value.is_a?(Date)
|
||||||
format_date(value)
|
format_date(value)
|
||||||
elsif value.is_a?(Time)
|
elsif value.is_a?(Time)
|
||||||
|
|||||||
+25
-13
@@ -145,8 +145,8 @@ class Issue < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Returns an unsaved copy of the issue
|
# Returns an unsaved copy of the issue
|
||||||
def copy(attributes=nil)
|
def copy(attributes=nil, copy_options={})
|
||||||
copy = self.class.new.copy_from(self)
|
copy = self.class.new.copy_from(self, copy_options)
|
||||||
copy.attributes = attributes if attributes
|
copy.attributes = attributes if attributes
|
||||||
copy
|
copy
|
||||||
end
|
end
|
||||||
@@ -509,18 +509,30 @@ class Issue < ActiveRecord::Base
|
|||||||
!relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?
|
!relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of status that user is able to apply
|
# Returns an array of statuses that user is able to apply
|
||||||
def new_statuses_allowed_to(user=User.current, include_default=false)
|
def new_statuses_allowed_to(user=User.current, include_default=false)
|
||||||
statuses = status.find_new_statuses_allowed_to(
|
if new_record? && @copied_from
|
||||||
user.admin ? Role.all : user.roles_for_project(project),
|
[IssueStatus.default, @copied_from.status].compact.uniq.sort
|
||||||
tracker,
|
else
|
||||||
author == user,
|
initial_status = nil
|
||||||
assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id
|
if new_record?
|
||||||
)
|
initial_status = IssueStatus.default
|
||||||
statuses << status unless statuses.empty?
|
elsif status_id_was
|
||||||
statuses << IssueStatus.default if include_default
|
initial_status = IssueStatus.find_by_id(status_id_was)
|
||||||
statuses = statuses.uniq.sort
|
end
|
||||||
blocked? ? statuses.reject {|s| s.is_closed?} : statuses
|
initial_status ||= status
|
||||||
|
|
||||||
|
statuses = initial_status.find_new_statuses_allowed_to(
|
||||||
|
user.admin ? Role.all : user.roles_for_project(project),
|
||||||
|
tracker,
|
||||||
|
author == user,
|
||||||
|
assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id
|
||||||
|
)
|
||||||
|
statuses << initial_status unless statuses.empty?
|
||||||
|
statuses << IssueStatus.default if include_default
|
||||||
|
statuses = statuses.compact.uniq.sort
|
||||||
|
blocked? ? statuses.reject {|s| s.is_closed?} : statuses
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def assigned_to_was
|
def assigned_to_was
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ class MailHandler < ActionMailer::Base
|
|||||||
super email
|
super email
|
||||||
end
|
end
|
||||||
|
|
||||||
|
cattr_accessor :ignored_emails_headers
|
||||||
|
@@ignored_emails_headers = {
|
||||||
|
'X-Auto-Response-Suppress' => 'OOF',
|
||||||
|
'Auto-Submitted' => 'auto-replied'
|
||||||
|
}
|
||||||
|
|
||||||
# Processes incoming emails
|
# Processes incoming emails
|
||||||
# Returns the created object (eg. an issue, a message) or false
|
# Returns the created object (eg. an issue, a message) or false
|
||||||
def receive(email)
|
def receive(email)
|
||||||
@@ -54,6 +60,16 @@ class MailHandler < ActionMailer::Base
|
|||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
# Ignore auto generated emails
|
||||||
|
self.class.ignored_emails_headers.each do |key, ignored_value|
|
||||||
|
value = email.header_string(key)
|
||||||
|
if value && value.to_s.downcase == ignored_value.downcase
|
||||||
|
if logger && logger.info
|
||||||
|
logger.info "MailHandler: ignoring email with #{key}:#{value} header"
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
@user = User.find_by_mail(sender_email) if sender_email.present?
|
@user = User.find_by_mail(sender_email) if sender_email.present?
|
||||||
if @user && !@user.active?
|
if @user && !@user.active?
|
||||||
if logger && logger.info
|
if logger && logger.info
|
||||||
|
|||||||
+12
-1
@@ -359,7 +359,7 @@ class Mailer < ActionMailer::Base
|
|||||||
|
|
||||||
issues_by_assignee = scope.all(:include => [:status, :assigned_to, :project, :tracker]).group_by(&:assigned_to)
|
issues_by_assignee = scope.all(:include => [:status, :assigned_to, :project, :tracker]).group_by(&:assigned_to)
|
||||||
issues_by_assignee.each do |assignee, issues|
|
issues_by_assignee.each do |assignee, issues|
|
||||||
deliver_reminder(assignee, issues, days) if assignee && assignee.active?
|
deliver_reminder(assignee, issues, days) if assignee.is_a?(User) && assignee.active?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -372,6 +372,17 @@ class Mailer < ActionMailer::Base
|
|||||||
ActionMailer::Base.perform_deliveries = was_enabled
|
ActionMailer::Base.perform_deliveries = was_enabled
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Sends emails synchronously in the given block
|
||||||
|
def self.with_synched_deliveries(&block)
|
||||||
|
saved_method = ActionMailer::Base.delivery_method
|
||||||
|
if m = saved_method.to_s.match(%r{^async_(.+)$})
|
||||||
|
ActionMailer::Base.delivery_method = m[1].to_sym
|
||||||
|
end
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
ActionMailer::Base.delivery_method = saved_method
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
def initialize_defaults(method_name)
|
def initialize_defaults(method_name)
|
||||||
super
|
super
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ class Message < ActiveRecord::Base
|
|||||||
:author_key => :author_id
|
:author_key => :author_id
|
||||||
acts_as_watchable
|
acts_as_watchable
|
||||||
|
|
||||||
attr_protected :locked, :sticky
|
|
||||||
validates_presence_of :board, :subject, :content
|
validates_presence_of :board, :subject, :content
|
||||||
validates_length_of :subject, :maximum => 255
|
validates_length_of :subject, :maximum => 255
|
||||||
validate :cannot_reply_to_locked_topic, :on => :create
|
validate :cannot_reply_to_locked_topic, :on => :create
|
||||||
@@ -50,7 +49,7 @@ class Message < ActiveRecord::Base
|
|||||||
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
|
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } }
|
||||||
|
|
||||||
safe_attributes 'subject', 'content'
|
safe_attributes 'subject', 'content'
|
||||||
safe_attributes 'locked', 'sticky',
|
safe_attributes 'locked', 'sticky', 'board_id',
|
||||||
:if => lambda {|message, user|
|
:if => lambda {|message, user|
|
||||||
user.allowed_to?(:edit_messages, message.project)
|
user.allowed_to?(:edit_messages, message.project)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -348,6 +348,11 @@ class User < Principal
|
|||||||
find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
|
find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns true if the default admin account can no longer be used
|
||||||
|
def self.default_admin_account_changed?
|
||||||
|
!User.active.find_by_login("admin").try(:check_password?, "admin")
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
name
|
name
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -60,6 +60,13 @@
|
|||||||
<p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p>
|
<p><label><%= h(custom_field.name) %></label> <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<% if @copy && @attachments_present %>
|
||||||
|
<p>
|
||||||
|
<label for='copy_attachments'><%= l(:label_copy_attachments) %></label>
|
||||||
|
<%= check_box_tag 'copy_attachments', '1', true %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
|
<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
<title><%=h html_title %></title>
|
<title><%=h html_title %></title>
|
||||||
<meta name="description" content="<%= Redmine::Info.app_name %>" />
|
<meta name="description" content="<%= Redmine::Info.app_name %>" />
|
||||||
<meta name="keywords" content="issue,bug,tracker" />
|
<meta name="keywords" content="issue,bug,tracker" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=9; IE=8; IE=7; IE=EDGE" />
|
||||||
<%= csrf_meta_tag %>
|
<%= csrf_meta_tag %>
|
||||||
<%= favicon %>
|
<%= favicon %>
|
||||||
<%= stylesheet_link_tag 'application', :media => 'all' %>
|
<%= stylesheet_link_tag 'application', :media => 'all' %>
|
||||||
|
|||||||
@@ -6,13 +6,17 @@
|
|||||||
<p><label for="message_subject"><%= l(:field_subject) %></label><br />
|
<p><label for="message_subject"><%= l(:field_subject) %></label><br />
|
||||||
<%= f.text_field :subject, :size => 120, :id => "message_subject" %>
|
<%= f.text_field :subject, :size => 120, :id => "message_subject" %>
|
||||||
|
|
||||||
<% if !replying && User.current.allowed_to?(:edit_messages, @project) %>
|
<% unless replying %>
|
||||||
|
<% if @message.safe_attribute? 'sticky' %>
|
||||||
<label><%= f.check_box :sticky %><%= l(:label_board_sticky) %></label>
|
<label><%= f.check_box :sticky %><%= l(:label_board_sticky) %></label>
|
||||||
|
<% end %>
|
||||||
|
<% if @message.safe_attribute? 'locked' %>
|
||||||
<label><%= f.check_box :locked %><%= l(:label_board_locked) %></label>
|
<label><%= f.check_box :locked %><%= l(:label_board_locked) %></label>
|
||||||
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<% if !replying && !@message.new_record? && User.current.allowed_to?(:edit_messages, @project) %>
|
<% if !replying && !@message.new_record? && @message.safe_attribute?('board_id') %>
|
||||||
<p><label><%= l(:label_board) %></label><br />
|
<p><label><%= l(:label_board) %></label><br />
|
||||||
<%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %></p>
|
<%= f.select :board_id, @project.boards.collect {|b| [b.name, b.id]} %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
# MySQL (default setup).
|
# Default setup is given for MySQL with ruby1.8. If you're running Redmine
|
||||||
|
# with MySQL and ruby1.9, replace the adapter name with `mysql2`.
|
||||||
|
# Examples for PostgreSQL and SQLite3 can be found at the end.
|
||||||
|
|
||||||
production:
|
production:
|
||||||
adapter: mysql
|
adapter: mysql
|
||||||
|
|||||||
@@ -1039,4 +1039,4 @@ fr:
|
|||||||
label_child_revision: Enfant
|
label_child_revision: Enfant
|
||||||
error_scm_annotate_big_text_file: Cette entrée ne peut pas être annotée car elle excède la taille maximale.
|
error_scm_annotate_big_text_file: Cette entrée ne peut pas être annotée car elle excède la taille maximale.
|
||||||
setting_repositories_encodings: Encodages des fichiers et des dépôts
|
setting_repositories_encodings: Encodages des fichiers et des dépôts
|
||||||
label_search_for_watchers: Search for watchers to add
|
label_search_for_watchers: Rechercher des observateurs
|
||||||
|
|||||||
@@ -1001,12 +1001,12 @@ zh:
|
|||||||
label_child_revision: 子修订
|
label_child_revision: 子修订
|
||||||
error_scm_annotate_big_text_file: 输入文本内容超长,无法输入。
|
error_scm_annotate_big_text_file: 输入文本内容超长,无法输入。
|
||||||
setting_default_issue_start_date_to_creation_date: 使用当前日期作为新问题的开始日期
|
setting_default_issue_start_date_to_creation_date: 使用当前日期作为新问题的开始日期
|
||||||
button_edit_section: Edit this section
|
button_edit_section: 编辑此区域
|
||||||
setting_repositories_encodings: Attachments and repositories encodings
|
setting_repositories_encodings: 附件和版本库编码
|
||||||
description_all_columns: All Columns
|
description_all_columns: 所有列
|
||||||
button_export: Export
|
button_export: 导出
|
||||||
label_export_options: "%{export_format} export options"
|
label_export_options: "%{export_format} 导出选项"
|
||||||
error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})
|
error_attachment_too_big: 该文件无法上传。超过文件大小限制 (%{max_size})
|
||||||
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
||||||
label_x_issues:
|
label_x_issues:
|
||||||
zero: 0 问题
|
zero: 0 问题
|
||||||
|
|||||||
@@ -339,6 +339,7 @@ ActionController::Routing::Routes.draw do |map|
|
|||||||
map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
|
map.resources :roles, :except => :show, :collection => {:permissions => [:get, :post]}
|
||||||
map.resources :enumerations, :except => :show
|
map.resources :enumerations, :except => :show
|
||||||
|
|
||||||
|
map.connect 'projects/:id/search', :controller => 'search', :action => 'index', :conditions => {:method => :get}
|
||||||
map.connect 'search', :controller => 'search', :action => 'index', :conditions => {:method => :get}
|
map.connect 'search', :controller => 'search', :action => 'index', :conditions => {:method => :get}
|
||||||
|
|
||||||
map.connect 'mail_handler', :controller => 'mail_handler',
|
map.connect 'mail_handler', :controller => 'mail_handler',
|
||||||
|
|||||||
+20
-6
@@ -4,13 +4,15 @@ Redmine - project management software
|
|||||||
Copyright (C) 2006-2012 Jean-Philippe Lang
|
Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||||
http://www.redmine.org/
|
http://www.redmine.org/
|
||||||
|
|
||||||
== TBD v1.4.0
|
== 2012-04-14 v1.4.0
|
||||||
|
|
||||||
* Defect #2719: Increase username length limit from 30 to 60
|
* Defect #2719: Increase username length limit from 30 to 60
|
||||||
* Defect #3087: Revision referring to issues across all projects
|
* Defect #3087: Revision referring to issues across all projects
|
||||||
* Defect #4824: Unable to connect (can't convert Net::LDAP::LdapError into String)
|
* Defect #4824: Unable to connect (can't convert Net::LDAP::LdapError into String)
|
||||||
|
* Defect #5058: reminder mails are not sent when delivery_method is :async_smtp
|
||||||
* Defect #6859: Moving issues to a tracker with different custom fields should let fill these fields
|
* Defect #6859: Moving issues to a tracker with different custom fields should let fill these fields
|
||||||
* Defect #7398: Error when trying to quick create a version with required custom field
|
* Defect #7398: Error when trying to quick create a version with required custom field
|
||||||
|
* Defect #7495: Python multiline comments highlighting problem in Repository browser
|
||||||
* Defect #7826: bigdecimal-segfault-fix.rb must be removed for Oracle
|
* Defect #7826: bigdecimal-segfault-fix.rb must be removed for Oracle
|
||||||
* Defect #7920: Attempted to update a stale object when copying a project
|
* Defect #7920: Attempted to update a stale object when copying a project
|
||||||
* Defect #8857: Git: Too long in fetching repositories after upgrade from 1.1 or new branch at first time
|
* Defect #8857: Git: Too long in fetching repositories after upgrade from 1.1 or new branch at first time
|
||||||
@@ -20,6 +22,7 @@ http://www.redmine.org/
|
|||||||
* Defect #9978: Japanese "permission_add_issue_watchers" is wrong
|
* Defect #9978: Japanese "permission_add_issue_watchers" is wrong
|
||||||
* Defect #10006: Email reminders are sent for closed issues
|
* Defect #10006: Email reminders are sent for closed issues
|
||||||
* Defect #10150: CSV export and spent time: rounding issue
|
* Defect #10150: CSV export and spent time: rounding issue
|
||||||
|
* Defect #10168: CSV export breaks custom columns
|
||||||
* Defect #10181: Issue context menu and bulk edit form show irrelevant statuses
|
* Defect #10181: Issue context menu and bulk edit form show irrelevant statuses
|
||||||
* Defect #10198: message_id regex in pop3.rb only recognizes Message-ID header (not Message-Id)
|
* Defect #10198: message_id regex in pop3.rb only recognizes Message-ID header (not Message-Id)
|
||||||
* Defect #10251: Description diff link in note details is relative when received by email
|
* Defect #10251: Description diff link in note details is relative when received by email
|
||||||
@@ -29,14 +32,12 @@ http://www.redmine.org/
|
|||||||
* Defect #10410: [Localization] Grammar issue of Simplified Chinese in zh.yml
|
* Defect #10410: [Localization] Grammar issue of Simplified Chinese in zh.yml
|
||||||
* Defect #10442: Ruby 1.9.3 Time Zone setting Internal error.
|
* Defect #10442: Ruby 1.9.3 Time Zone setting Internal error.
|
||||||
* Defect #10467: Confusing behavior while moving issue to a project with disabled Issues module
|
* Defect #10467: Confusing behavior while moving issue to a project with disabled Issues module
|
||||||
* Defect #10505: Error when exporting to PDF with NoMethodError (undefined method `downcase' for nil:NilClass)
|
|
||||||
* Defect #10554: Defect symbols when exporting tasks in pdf
|
|
||||||
* Defect #10575: Uploading of attachments which filename contains non-ASCII chars fails with Ruby 1.9
|
* Defect #10575: Uploading of attachments which filename contains non-ASCII chars fails with Ruby 1.9
|
||||||
* Defect #10590: WikiContent::Version#text return string with #<Encoding:ASCII-8BIT> when uncompressed
|
* Defect #10590: WikiContent::Version#text return string with #<Encoding:ASCII-8BIT> when uncompressed
|
||||||
* Defect #10591: Dutch "label_file_added" translation is wrong
|
|
||||||
* Defect #10593: Error: 'incompatible character encodings: UTF-8 and ASCII-8BIT' (old annoing issue) on ruby-1.9.3
|
* Defect #10593: Error: 'incompatible character encodings: UTF-8 and ASCII-8BIT' (old annoing issue) on ruby-1.9.3
|
||||||
* Defect #10600: Watchers search generates an Internal error
|
* Defect #10600: Watchers search generates an Internal error
|
||||||
* Defect #10602: Attachment link has get parameter :class
|
* Defect #10605: Bulk edit selected issues does not allow selection of blank values for custom fields
|
||||||
|
* Defect #10619: When changing status before tracker, it shows improper status
|
||||||
* Feature #779: Multiple SCM per project
|
* Feature #779: Multiple SCM per project
|
||||||
* Feature #971: Add "Spent time" column to query
|
* Feature #971: Add "Spent time" column to query
|
||||||
* Feature #1060: Add a LDAP-filter using external auth sources
|
* Feature #1060: Add a LDAP-filter using external auth sources
|
||||||
@@ -63,6 +64,7 @@ http://www.redmine.org/
|
|||||||
* Feature #6296: Bulk-edit custom fields through context menu
|
* Feature #6296: Bulk-edit custom fields through context menu
|
||||||
* Feature #6386: Issue mail should render the HTML version of the issue details
|
* Feature #6386: Issue mail should render the HTML version of the issue details
|
||||||
* Feature #6449: Edit a wiki page's parent on the edit page
|
* Feature #6449: Edit a wiki page's parent on the edit page
|
||||||
|
* Feature #6555: Double-click on "Submit" and "Save" buttons should not send two requests to server
|
||||||
* Feature #7361: Highlight active query in the side bar
|
* Feature #7361: Highlight active query in the side bar
|
||||||
* Feature #7420: Rest API for projects members
|
* Feature #7420: Rest API for projects members
|
||||||
* Feature #7603: Please make editing issues more obvious than "Change properties (More)"
|
* Feature #7603: Please make editing issues more obvious than "Change properties (More)"
|
||||||
@@ -74,20 +76,32 @@ http://www.redmine.org/
|
|||||||
* Feature #9995: Time entries insertion, "Create and continue" button
|
* Feature #9995: Time entries insertion, "Create and continue" button
|
||||||
* Feature #10020: Enable global time logging at /time_entries/new
|
* Feature #10020: Enable global time logging at /time_entries/new
|
||||||
* Feature #10042: Bulk change private flag
|
* Feature #10042: Bulk change private flag
|
||||||
* Feature #10046: Update installation doc on release
|
|
||||||
* Feature #10126: Add members of subprojects in the assignee and author filters
|
* Feature #10126: Add members of subprojects in the assignee and author filters
|
||||||
* Feature #10131: Include custom fiels in time entries API responses
|
* Feature #10131: Include custom fiels in time entries API responses
|
||||||
* Feature #10207: Git: use default branch from HEAD
|
* Feature #10207: Git: use default branch from HEAD
|
||||||
* Feature #10208: Estonian translation
|
* Feature #10208: Estonian translation
|
||||||
* Feature #10253: Better handling of attachments when validation fails
|
* Feature #10253: Better handling of attachments when validation fails
|
||||||
* Feature #10350: Bulk copy should allow for changing the target version
|
* Feature #10350: Bulk copy should allow for changing the target version
|
||||||
|
* Feature #10607: Ignore out-of-office incoming emails
|
||||||
|
* Feature #10635: Adding time like "123 Min" is invalid
|
||||||
* Patch #9998: Make attachement "Optional Description" less wide
|
* Patch #9998: Make attachement "Optional Description" less wide
|
||||||
* Patch #10066: i18n not working with russian gem
|
* Patch #10066: i18n not working with russian gem
|
||||||
|
* Patch #10128: Disable IE 8 compatibility mode to fix wrong div.autoscroll scroll bar behaviour
|
||||||
* Patch #10155: Russian translation changed
|
* Patch #10155: Russian translation changed
|
||||||
* Patch #10464: Enhanced PDF output for Issues list
|
* Patch #10464: Enhanced PDF output for Issues list
|
||||||
* Patch #10470: Efficiently process new git revisions in a single batch
|
* Patch #10470: Efficiently process new git revisions in a single batch
|
||||||
* Patch #10513: Dutch translation improvement
|
* Patch #10513: Dutch translation improvement
|
||||||
|
|
||||||
|
== 2012-04-14 v1.3.3
|
||||||
|
|
||||||
|
* Defect #10505: Error when exporting to PDF with NoMethodError (undefined method `downcase' for nil:NilClass)
|
||||||
|
* Defect #10554: Defect symbols when exporting tasks in pdf
|
||||||
|
* Defect #10564: Unable to change locked, sticky flags and board when editing a message
|
||||||
|
* Defect #10591: Dutch "label_file_added" translation is wrong
|
||||||
|
* Defect #10622: "Default administrator account changed" is always true
|
||||||
|
* Patch #10555: rake redmine:send_reminders aborted if issue assigned to group
|
||||||
|
* Patch #10611: Simplified Chinese translations for 1.3-stable
|
||||||
|
|
||||||
== 2012-03-11 v1.3.2
|
== 2012-03-11 v1.3.2
|
||||||
|
|
||||||
* Defect #8194: {{toc}} uses identical anchors for subsections with the same name
|
* Defect #8194: {{toc}} uses identical anchors for subsections with the same name
|
||||||
|
|||||||
@@ -31,6 +31,10 @@ Optional:
|
|||||||
of the rmagick gem using:
|
of the rmagick gem using:
|
||||||
bundle install --without development test rmagick
|
bundle install --without development test rmagick
|
||||||
|
|
||||||
|
If you need to load some gems that are not required by Redmine core (eg. fcgi),
|
||||||
|
you can create a file named Gemfile.local at the root of your redmine directory.
|
||||||
|
It will be loaded automatically when running `bundle install`.
|
||||||
|
|
||||||
3. Create an empty utf8 encoded database: "redmine" for example
|
3. Create an empty utf8 encoded database: "redmine" for example
|
||||||
|
|
||||||
4. Configure the database parameters in config/database.yml
|
4. Configure the database parameters in config/database.yml
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ module Redmine #:nodoc:
|
|||||||
# 2:30 => 2.5
|
# 2:30 => 2.5
|
||||||
s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 }
|
s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 }
|
||||||
# 2h30, 2h, 30m => 2.5, 2, 0.5
|
# 2h30, 2h, 30m => 2.5, 2, 0.5
|
||||||
s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] }
|
s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}i) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] }
|
||||||
end
|
end
|
||||||
# 2,5 => 2.5
|
# 2,5 => 2.5
|
||||||
s.gsub!(',', '.')
|
s.gsub!(',', '.')
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ module Redmine
|
|||||||
# Should not return line numbers nor outer pre tag
|
# Should not return line numbers nor outer pre tag
|
||||||
def highlight_by_filename(text, filename)
|
def highlight_by_filename(text, filename)
|
||||||
language = ::CodeRay::FileType[filename]
|
language = ::CodeRay::FileType[filename]
|
||||||
language ? ::CodeRay.scan(text, language).html : ERB::Util.h(text)
|
language ? ::CodeRay.scan(text, language).html(:break_lines => true) : ERB::Util.h(text)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Highlights +text+ using +language+ syntax
|
# Highlights +text+ using +language+ syntax
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module Redmine
|
|||||||
# * official release: nil
|
# * official release: nil
|
||||||
# * stable branch: stable
|
# * stable branch: stable
|
||||||
# * trunk: devel
|
# * trunk: devel
|
||||||
BRANCH = 'devel'
|
BRANCH = 'stable'
|
||||||
|
|
||||||
def self.revision
|
def self.revision
|
||||||
revision = nil
|
revision = nil
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ module Redmine
|
|||||||
end
|
end
|
||||||
|
|
||||||
def link_to(name, options={})
|
def link_to(name, options={})
|
||||||
url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {})
|
url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {}).except('page')
|
||||||
caption = options.delete(:caption) || name
|
caption = options.delete(:caption) || name
|
||||||
html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options)
|
html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options)
|
||||||
@view.content_tag('span', @view.link_to(caption, url, html_options))
|
@view.content_tag('span', @view.link_to(caption, url, html_options))
|
||||||
|
|||||||
+2
-2
@@ -48,8 +48,8 @@ namespace :ci do
|
|||||||
test_conf = { 'adapter' => (RUBY_VERSION >= '1.9' ? 'mysql2' : 'mysql'), 'database' => test_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins', 'encoding' => 'utf8' }
|
test_conf = { 'adapter' => (RUBY_VERSION >= '1.9' ? 'mysql2' : 'mysql'), 'database' => test_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins', 'encoding' => 'utf8' }
|
||||||
when 'postgresql'
|
when 'postgresql'
|
||||||
raise "Error creating databases" unless
|
raise "Error creating databases" unless
|
||||||
system(%|psql -U jenkins -d postgres -c "create database #{dev_db_name} owner jenkins encoding 'UTF8';|) &&
|
system(%|psql -U jenkins -d postgres -c "create database #{dev_db_name} owner jenkins encoding 'UTF8';"|) &&
|
||||||
system(%|psql -U jenkins -d postgres -c "create database #{test_db_name} owner jenkins encoding 'UTF8';|)
|
system(%|psql -U jenkins -d postgres -c "create database #{test_db_name} owner jenkins encoding 'UTF8';"|)
|
||||||
dev_conf = { 'adapter' => 'postgresql', 'database' => dev_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins' }
|
dev_conf = { 'adapter' => 'postgresql', 'database' => dev_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins' }
|
||||||
test_conf = { 'adapter' => 'postgresql', 'database' => test_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins' }
|
test_conf = { 'adapter' => 'postgresql', 'database' => test_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins' }
|
||||||
when 'sqlite3'
|
when 'sqlite3'
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ namespace :redmine do
|
|||||||
options[:tracker] = ENV['tracker'].to_i if ENV['tracker']
|
options[:tracker] = ENV['tracker'].to_i if ENV['tracker']
|
||||||
options[:users] = (ENV['users'] || '').split(',').each(&:strip!)
|
options[:users] = (ENV['users'] || '').split(',').each(&:strip!)
|
||||||
|
|
||||||
Mailer.reminders(options)
|
Mailer.with_synched_deliveries do
|
||||||
|
Mailer.reminders(options)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -520,4 +520,16 @@ function hideOnLoad() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addFormObserversForDoubleSubmit() {
|
||||||
|
$$('form[method=post]').each(function(el) {
|
||||||
|
Event.observe(el, 'submit', function(e) {
|
||||||
|
var form = Event.element(e);
|
||||||
|
form.select('input[type=submit]').each(function(btn) {
|
||||||
|
btn.disable();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Event.observe(window, 'load', hideOnLoad);
|
Event.observe(window, 'load', hideOnLoad);
|
||||||
|
Event.observe(window, 'load', addFormObserversForDoubleSubmit);
|
||||||
|
|||||||
+35
-38
@@ -110,85 +110,74 @@ div.action_A { background: #bfb }
|
|||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
}
|
}
|
||||||
.syntaxhl .code pre { overflow: auto }
|
.syntaxhl .code pre { overflow: auto }
|
||||||
.syntaxhl .debug { color:white ! important; background:blue ! important; }
|
.syntaxhl .debug { color: white !important; background: blue !important; }
|
||||||
|
|
||||||
.syntaxhl .attribute-name { color:#b48 }
|
|
||||||
.syntaxhl .annotation { color:#007 }
|
.syntaxhl .annotation { color:#007 }
|
||||||
|
.syntaxhl .attribute-name { color:#b48 }
|
||||||
.syntaxhl .attribute-value { color:#700 }
|
.syntaxhl .attribute-value { color:#700 }
|
||||||
.syntaxhl .binary { color:#509 }
|
.syntaxhl .binary { color:#509 }
|
||||||
|
.syntaxhl .char .content { color:#D20 }
|
||||||
|
.syntaxhl .char .delimiter { color:#710 }
|
||||||
|
.syntaxhl .char { color:#D20 }
|
||||||
|
.syntaxhl .class { color:#B06; font-weight:bold }
|
||||||
|
.syntaxhl .class-variable { color:#369 }
|
||||||
|
.syntaxhl .color { color:#0A0 }
|
||||||
.syntaxhl .comment { color:#777 }
|
.syntaxhl .comment { color:#777 }
|
||||||
.syntaxhl .comment .char { color:#444 }
|
.syntaxhl .comment .char { color:#444 }
|
||||||
.syntaxhl .comment .delimiter { color:#444 }
|
.syntaxhl .comment .delimiter { color:#444 }
|
||||||
|
|
||||||
.syntaxhl .char { color:#D20 }
|
|
||||||
.syntaxhl .char .content { color:#D20 }
|
|
||||||
.syntaxhl .char .delimiter { color:#710 }
|
|
||||||
|
|
||||||
.syntaxhl .class { color:#B06; font-weight:bold }
|
|
||||||
.syntaxhl .complex { color:#A08 }
|
.syntaxhl .complex { color:#A08 }
|
||||||
.syntaxhl .constant { color:#036; font-weight:bold }
|
.syntaxhl .constant { color:#036; font-weight:bold }
|
||||||
.syntaxhl .color { color:#0A0 }
|
|
||||||
.syntaxhl .class-variable { color:#369 }
|
|
||||||
.syntaxhl .decorator { color:#B0B }
|
.syntaxhl .decorator { color:#B0B }
|
||||||
.syntaxhl .definition { color:#099; font-weight:bold }
|
.syntaxhl .definition { color:#099; font-weight:bold }
|
||||||
.syntaxhl .directive { color:#088; font-weight:bold }
|
|
||||||
.syntaxhl .delimiter { color:black }
|
.syntaxhl .delimiter { color:black }
|
||||||
|
.syntaxhl .directive { color:#088; font-weight:bold }
|
||||||
.syntaxhl .doc { color:#970 }
|
.syntaxhl .doc { color:#970 }
|
||||||
.syntaxhl .doctype { color:#34b }
|
|
||||||
.syntaxhl .doc-string { color:#D42; font-weight:bold }
|
.syntaxhl .doc-string { color:#D42; font-weight:bold }
|
||||||
.syntaxhl .escape { color:#666 }
|
.syntaxhl .doctype { color:#34b }
|
||||||
.syntaxhl .entity { color:#800; font-weight:bold }
|
.syntaxhl .entity { color:#800; font-weight:bold }
|
||||||
.syntaxhl .error { color:#F00; background-color:#FAA }
|
.syntaxhl .error { color:#F00; background-color:#FAA }
|
||||||
|
.syntaxhl .escape { color:#666 }
|
||||||
.syntaxhl .exception { color:#C00; font-weight:bold }
|
.syntaxhl .exception { color:#C00; font-weight:bold }
|
||||||
.syntaxhl .float { color:#60E }
|
.syntaxhl .float { color:#60E }
|
||||||
.syntaxhl .function { color:#06B; font-weight:bold }
|
.syntaxhl .function { color:#06B; font-weight:bold }
|
||||||
.syntaxhl .global-variable { color:#d70 }
|
.syntaxhl .global-variable { color:#d70 }
|
||||||
.syntaxhl .hex { color:#02b }
|
.syntaxhl .hex { color:#02b }
|
||||||
.syntaxhl .integer { color:#00D }
|
|
||||||
.syntaxhl .include { color:#B44; font-weight:bold }
|
|
||||||
.syntaxhl .imaginary { color:#f00 }
|
.syntaxhl .imaginary { color:#f00 }
|
||||||
|
.syntaxhl .include { color:#B44; font-weight:bold }
|
||||||
.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
|
.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black }
|
||||||
.syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
|
.syntaxhl .inline-delimiter { font-weight: bold; color: #666 }
|
||||||
|
|
||||||
.syntaxhl .instance-variable { color:#33B }
|
.syntaxhl .instance-variable { color:#33B }
|
||||||
|
.syntaxhl .integer { color:#00D }
|
||||||
|
.syntaxhl .key .char { color: #60f }
|
||||||
|
.syntaxhl .key .delimiter { color: #404 }
|
||||||
|
.syntaxhl .key { color: #606 }
|
||||||
|
.syntaxhl .keyword { color:#080; font-weight:bold }
|
||||||
.syntaxhl .label { color:#970; font-weight:bold }
|
.syntaxhl .label { color:#970; font-weight:bold }
|
||||||
.syntaxhl .local-variable { color:#963 }
|
.syntaxhl .local-variable { color:#963 }
|
||||||
.syntaxhl .namespace { color:#707; font-weight:bold }
|
.syntaxhl .namespace { color:#707; font-weight:bold }
|
||||||
.syntaxhl .octal { color:#40E }
|
.syntaxhl .octal { color:#40E }
|
||||||
.syntaxhl .operator { }
|
.syntaxhl .operator { }
|
||||||
.syntaxhl .predefined-constant { color:#069 }
|
|
||||||
.syntaxhl .predefined { color:#369; font-weight:bold }
|
.syntaxhl .predefined { color:#369; font-weight:bold }
|
||||||
|
.syntaxhl .predefined-constant { color:#069 }
|
||||||
.syntaxhl .predefined-type { color:#0a5; font-weight:bold }
|
.syntaxhl .predefined-type { color:#0a5; font-weight:bold }
|
||||||
.syntaxhl .preprocessor { color:#579 }
|
.syntaxhl .preprocessor { color:#579 }
|
||||||
.syntaxhl .pseudo-class { color:#00C; font-weight:bold }
|
.syntaxhl .pseudo-class { color:#00C; font-weight:bold }
|
||||||
.syntaxhl .reserved { color:#080; font-weight:bold }
|
|
||||||
|
|
||||||
.syntaxhl .key .char { color: #60f }
|
|
||||||
.syntaxhl .key .delimiter { color: #404 }
|
|
||||||
.syntaxhl .key { color: #606 }
|
|
||||||
.syntaxhl .keyword { color:#080; font-weight:bold }
|
|
||||||
|
|
||||||
.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
|
|
||||||
.syntaxhl .regexp .content { color:#808 }
|
.syntaxhl .regexp .content { color:#808 }
|
||||||
.syntaxhl .regexp .delimiter { color:#404 }
|
.syntaxhl .regexp .delimiter { color:#404 }
|
||||||
.syntaxhl .regexp .modifier { color:#C2C }
|
.syntaxhl .regexp .modifier { color:#C2C }
|
||||||
|
.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); }
|
||||||
.syntaxhl .string { background-color:hsla(0,100%,50%,0.05); }
|
.syntaxhl .reserved { color:#080; font-weight:bold }
|
||||||
.syntaxhl .string .content { color: #D20 }
|
|
||||||
.syntaxhl .string .char { color: #b0b }
|
|
||||||
.syntaxhl .string .delimiter { color: #710 }
|
|
||||||
.syntaxhl .string .modifier { color: #E40 }
|
|
||||||
|
|
||||||
.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
|
|
||||||
.syntaxhl .shell .content { color:#2B2 }
|
.syntaxhl .shell .content { color:#2B2 }
|
||||||
.syntaxhl .shell .delimiter { color:#161 }
|
.syntaxhl .shell .delimiter { color:#161 }
|
||||||
|
.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); }
|
||||||
.syntaxhl .symbol { color:#A60 }
|
.syntaxhl .string .char { color: #b0b }
|
||||||
|
.syntaxhl .string .content { color: #D20 }
|
||||||
|
.syntaxhl .string .delimiter { color: #710 }
|
||||||
|
.syntaxhl .string .modifier { color: #E40 }
|
||||||
|
.syntaxhl .string { background-color:hsla(0,100%,50%,0.05); }
|
||||||
.syntaxhl .symbol .content { color:#A60 }
|
.syntaxhl .symbol .content { color:#A60 }
|
||||||
.syntaxhl .symbol .delimiter { color:#630 }
|
.syntaxhl .symbol .delimiter { color:#630 }
|
||||||
|
.syntaxhl .symbol { color:#A60 }
|
||||||
.syntaxhl .tag { color:#070 }
|
.syntaxhl .tag { color:#070 }
|
||||||
.syntaxhl .type { color:#339; font-weight:bold }
|
.syntaxhl .type { color:#339; font-weight:bold }
|
||||||
.syntaxhl .value { color: #088; }
|
.syntaxhl .value { color: #088; }
|
||||||
@@ -199,3 +188,11 @@ div.action_A { background: #bfb }
|
|||||||
.syntaxhl .change { color: #bbf; background: #007; }
|
.syntaxhl .change { color: #bbf; background: #007; }
|
||||||
.syntaxhl .head { color: #f8f; background: #505 }
|
.syntaxhl .head { color: #f8f; background: #505 }
|
||||||
.syntaxhl .head .filename { color: white; }
|
.syntaxhl .head .filename { color: white; }
|
||||||
|
|
||||||
|
.syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; }
|
||||||
|
.syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; }
|
||||||
|
|
||||||
|
.syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold }
|
||||||
|
.syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold }
|
||||||
|
.syntaxhl .change .change { color: #88f }
|
||||||
|
.syntaxhl .head .head { color: #f4f }
|
||||||
|
|||||||
@@ -48,6 +48,10 @@ class IssueRelationsControllerTest < ActionController::TestCase
|
|||||||
post :create, :issue_id => 1,
|
post :create, :issue_id => 1,
|
||||||
:relation => {:issue_to_id => '2', :relation_type => 'relates', :delay => ''}
|
:relation => {:issue_to_id => '2', :relation_type => 'relates', :delay => ''}
|
||||||
end
|
end
|
||||||
|
relation = IssueRelation.first(:order => 'id DESC')
|
||||||
|
assert_equal 1, relation.issue_from_id
|
||||||
|
assert_equal 2, relation.issue_to_id
|
||||||
|
assert_equal 'relates', relation.relation_type
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_xhr
|
def test_create_xhr
|
||||||
@@ -61,6 +65,9 @@ class IssueRelationsControllerTest < ActionController::TestCase
|
|||||||
assert_select 'tr', 2 # relations
|
assert_select 'tr', 2 # relations
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
relation = IssueRelation.first(:order => 'id DESC')
|
||||||
|
assert_equal 3, relation.issue_from_id
|
||||||
|
assert_equal 1, relation.issue_to_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_should_accept_id_with_hash
|
def test_create_should_accept_id_with_hash
|
||||||
@@ -69,6 +76,18 @@ class IssueRelationsControllerTest < ActionController::TestCase
|
|||||||
post :create, :issue_id => 1,
|
post :create, :issue_id => 1,
|
||||||
:relation => {:issue_to_id => '#2', :relation_type => 'relates', :delay => ''}
|
:relation => {:issue_to_id => '#2', :relation_type => 'relates', :delay => ''}
|
||||||
end
|
end
|
||||||
|
relation = IssueRelation.first(:order => 'id DESC')
|
||||||
|
assert_equal 2, relation.issue_to_id
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_create_should_strip_id
|
||||||
|
assert_difference 'IssueRelation.count' do
|
||||||
|
@request.session[:user_id] = 3
|
||||||
|
post :create, :issue_id => 1,
|
||||||
|
:relation => {:issue_to_id => ' 2 ', :relation_type => 'relates', :delay => ''}
|
||||||
|
end
|
||||||
|
relation = IssueRelation.first(:order => 'id DESC')
|
||||||
|
assert_equal 2, relation.issue_to_id
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_should_not_break_with_non_numerical_id
|
def test_create_should_not_break_with_non_numerical_id
|
||||||
|
|||||||
@@ -305,6 +305,15 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_response :success
|
assert_response :success
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_index_should_omit_page_param_in_export_links
|
||||||
|
get :index, :page => 2
|
||||||
|
assert_response :success
|
||||||
|
assert_select 'a.atom[href=/issues.atom]'
|
||||||
|
assert_select 'a.csv[href=/issues.csv]'
|
||||||
|
assert_select 'a.pdf[href=/issues.pdf]'
|
||||||
|
assert_select 'form#csv-export-form[action=/issues.csv]'
|
||||||
|
end
|
||||||
|
|
||||||
def test_index_csv
|
def test_index_csv
|
||||||
get :index, :format => 'csv'
|
get :index, :format => 'csv'
|
||||||
assert_response :success
|
assert_response :success
|
||||||
@@ -1363,6 +1372,22 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'This is the test_new issue', issue.subject
|
assert_equal 'This is the test_new issue', issue.subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_update_new_form_should_propose_transitions_based_on_initial_status
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
Workflow.delete_all
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 2)
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 1, :new_status_id => 5)
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4)
|
||||||
|
|
||||||
|
xhr :post, :new, :project_id => 1,
|
||||||
|
:issue => {:tracker_id => 1,
|
||||||
|
:status_id => 5,
|
||||||
|
:subject => 'This is an issue'}
|
||||||
|
|
||||||
|
assert_equal 5, assigns(:issue).status_id
|
||||||
|
assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
|
||||||
|
end
|
||||||
|
|
||||||
def test_post_create
|
def test_post_create
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
assert_difference 'Issue.count' do
|
assert_difference 'Issue.count' do
|
||||||
@@ -2171,6 +2196,23 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'This is the test_new issue', issue.subject
|
assert_equal 'This is the test_new issue', issue.subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_update_edit_form_should_propose_transitions_based_on_initial_status
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
Workflow.delete_all
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 1)
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 2, :new_status_id => 5)
|
||||||
|
Workflow.create!(:role_id => 1, :tracker_id => 2, :old_status_id => 5, :new_status_id => 4)
|
||||||
|
|
||||||
|
xhr :put, :new, :project_id => 1,
|
||||||
|
:id => 2,
|
||||||
|
:issue => {:tracker_id => 2,
|
||||||
|
:status_id => 5,
|
||||||
|
:subject => 'This is an issue'}
|
||||||
|
|
||||||
|
assert_equal 5, assigns(:issue).status_id
|
||||||
|
assert_equal [1,2,5], assigns(:allowed_statuses).map(&:id).sort
|
||||||
|
end
|
||||||
|
|
||||||
def test_update_edit_form_with_project_change
|
def test_update_edit_form_with_project_change
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
xhr :put, :new, :project_id => 1,
|
xhr :put, :new, :project_id => 1,
|
||||||
@@ -2665,7 +2707,7 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
:attributes => {:name => "issue[custom_field_values][#{field.id}]"},
|
:attributes => {:name => "issue[custom_field_values][#{field.id}]"},
|
||||||
:children => {
|
:children => {
|
||||||
:only => {:tag => 'option'},
|
:only => {:tag => 'option'},
|
||||||
:count => Project.find(1).users.count + 1
|
:count => Project.find(1).users.count + 2 # "no change" + "none" options
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2681,7 +2723,7 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
:attributes => {:name => "issue[custom_field_values][#{field.id}]"},
|
:attributes => {:name => "issue[custom_field_values][#{field.id}]"},
|
||||||
:children => {
|
:children => {
|
||||||
:only => {:tag => 'option'},
|
:only => {:tag => 'option'},
|
||||||
:count => Project.find(1).shared_versions.count + 1
|
:count => Project.find(1).shared_versions.count + 2 # "no change" + "none" options
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2698,7 +2740,7 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
:attributes => {:name => "issue[custom_field_values][1][]"},
|
:attributes => {:name => "issue[custom_field_values][1][]"},
|
||||||
:children => {
|
:children => {
|
||||||
:only => {:tag => 'option'},
|
:only => {:tag => 'option'},
|
||||||
:count => 3
|
:count => field.possible_values.size + 1 # "none" options
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -2924,6 +2966,17 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal '777', journal.details.first.value
|
assert_equal '777', journal.details.first.value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_bulk_update_custom_field_to_blank
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing custom field',
|
||||||
|
:issue => {:priority_id => '',
|
||||||
|
:assigned_to_id => '',
|
||||||
|
:custom_field_values => {'1' => '__none__'}}
|
||||||
|
assert_response 302
|
||||||
|
assert_equal '', Issue.find(1).custom_field_value(1)
|
||||||
|
assert_equal '', Issue.find(3).custom_field_value(1)
|
||||||
|
end
|
||||||
|
|
||||||
def test_bulk_update_multi_custom_field
|
def test_bulk_update_multi_custom_field
|
||||||
field = CustomField.find(1)
|
field = CustomField.find(1)
|
||||||
field.update_attribute :multiple, true
|
field.update_attribute :multiple, true
|
||||||
@@ -2942,6 +2995,20 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_nil Issue.find(2).custom_field_value(1)
|
assert_nil Issue.find(2).custom_field_value(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_bulk_update_multi_custom_field_to_blank
|
||||||
|
field = CustomField.find(1)
|
||||||
|
field.update_attribute :multiple, true
|
||||||
|
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
post :bulk_update, :ids => [1, 3], :notes => 'Bulk editing multi custom field',
|
||||||
|
:issue => {:priority_id => '',
|
||||||
|
:assigned_to_id => '',
|
||||||
|
:custom_field_values => {'1' => ['__none__']}}
|
||||||
|
assert_response 302
|
||||||
|
assert_equal [''], Issue.find(1).custom_field_value(1)
|
||||||
|
assert_equal [''], Issue.find(3).custom_field_value(1)
|
||||||
|
end
|
||||||
|
|
||||||
def test_bulk_update_unassign
|
def test_bulk_update_unassign
|
||||||
assert_not_nil Issue.find(2).assigned_to
|
assert_not_nil Issue.find(2).assigned_to
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
@@ -2990,6 +3057,19 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'Failed to save 1 issue(s) on 2 selected: #2.', flash[:error]
|
assert_equal 'Failed to save 1 issue(s) on 2 selected: #2.', flash[:error]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_get_bulk_copy
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get :bulk_edit, :ids => [1, 2, 3], :copy => '1'
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'bulk_edit'
|
||||||
|
|
||||||
|
issues = assigns(:issues)
|
||||||
|
assert_not_nil issues
|
||||||
|
assert_equal [1, 2, 3], issues.map(&:id).sort
|
||||||
|
|
||||||
|
assert_select 'input[name=copy_attachments]'
|
||||||
|
end
|
||||||
|
|
||||||
def test_bulk_copy_to_another_project
|
def test_bulk_copy_to_another_project
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
assert_difference 'Issue.count', 2 do
|
assert_difference 'Issue.count', 2 do
|
||||||
@@ -2998,27 +3078,41 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
assert_redirected_to '/projects/ecookbook/issues'
|
assert_redirected_to '/projects/ecookbook/issues'
|
||||||
|
|
||||||
|
copies = Issue.all(:order => 'id DESC', :limit => issues.size)
|
||||||
|
copies.each do |copy|
|
||||||
|
assert_equal 2, copy.project_id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bulk_copy_should_allow_not_changing_the_issue_attributes
|
def test_bulk_copy_should_allow_not_changing_the_issue_attributes
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
issue_before_move = Issue.find(1)
|
issues = [
|
||||||
assert_difference 'Issue.count', 1 do
|
Issue.create!(:project_id => 1, :tracker_id => 1, :status_id => 1, :priority_id => 2, :subject => 'issue 1', :author_id => 1, :assigned_to_id => nil),
|
||||||
assert_no_difference 'Project.find(1).issues.count' do
|
Issue.create!(:project_id => 2, :tracker_id => 3, :status_id => 2, :priority_id => 1, :subject => 'issue 2', :author_id => 2, :assigned_to_id => 3)
|
||||||
post :bulk_update, :ids => [1], :copy => '1',
|
]
|
||||||
:issue => {
|
|
||||||
:project_id => '2', :tracker_id => '', :assigned_to_id => '',
|
assert_difference 'Issue.count', issues.size do
|
||||||
:status_id => '', :start_date => '', :due_date => ''
|
post :bulk_update, :ids => issues.map(&:id), :copy => '1',
|
||||||
}
|
:issue => {
|
||||||
end
|
:project_id => '', :tracker_id => '', :assigned_to_id => '',
|
||||||
|
:status_id => '', :start_date => '', :due_date => ''
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
copies = Issue.all(:order => 'id DESC', :limit => issues.size)
|
||||||
|
issues.each do |orig|
|
||||||
|
copy = copies.detect {|c| c.subject == orig.subject}
|
||||||
|
assert_not_nil copy
|
||||||
|
assert_equal orig.project_id, copy.project_id
|
||||||
|
assert_equal orig.tracker_id, copy.tracker_id
|
||||||
|
assert_equal orig.status_id, copy.status_id
|
||||||
|
assert_equal orig.assigned_to_id, copy.assigned_to_id
|
||||||
|
assert_equal orig.priority_id, copy.priority_id
|
||||||
end
|
end
|
||||||
issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2})
|
|
||||||
assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id
|
|
||||||
assert_equal issue_before_move.status_id, issue_after_move.status_id
|
|
||||||
assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bulk_copy_should_allow_changing_the_issue_attributes
|
def test_bulk_copy_should_allow_changing_the_issue_attributes
|
||||||
# Fixes random test failure with Mysql
|
# Fixes random test failure with Mysql
|
||||||
# where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
|
# where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2})
|
||||||
# doesn't return the expected results
|
# doesn't return the expected results
|
||||||
@@ -3030,7 +3124,7 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
post :bulk_update, :ids => [1, 2], :copy => '1',
|
post :bulk_update, :ids => [1, 2], :copy => '1',
|
||||||
:issue => {
|
:issue => {
|
||||||
:project_id => '2', :tracker_id => '', :assigned_to_id => '4',
|
:project_id => '2', :tracker_id => '', :assigned_to_id => '4',
|
||||||
:status_id => '3', :start_date => '2009-12-01', :due_date => '2009-12-31'
|
:status_id => '1', :start_date => '2009-12-01', :due_date => '2009-12-31'
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -3040,7 +3134,7 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
copied_issues.each do |issue|
|
copied_issues.each do |issue|
|
||||||
assert_equal 2, issue.project_id, "Project is incorrect"
|
assert_equal 2, issue.project_id, "Project is incorrect"
|
||||||
assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
|
assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect"
|
||||||
assert_equal 3, issue.status_id, "Status is incorrect"
|
assert_equal 1, issue.status_id, "Status is incorrect"
|
||||||
assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
|
assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect"
|
||||||
assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
|
assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect"
|
||||||
end
|
end
|
||||||
@@ -3064,6 +3158,36 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'Copying one issue', journal.notes
|
assert_equal 'Copying one issue', journal.notes
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_bulk_copy_should_allow_not_copying_the_attachments
|
||||||
|
attachment_count = Issue.find(3).attachments.size
|
||||||
|
assert attachment_count > 0
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
|
||||||
|
assert_difference 'Issue.count', 1 do
|
||||||
|
assert_no_difference 'Attachment.count' do
|
||||||
|
post :bulk_update, :ids => [3], :copy => '1',
|
||||||
|
:issue => {
|
||||||
|
:project_id => ''
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_bulk_copy_should_allow_copying_the_attachments
|
||||||
|
attachment_count = Issue.find(3).attachments.size
|
||||||
|
assert attachment_count > 0
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
|
||||||
|
assert_difference 'Issue.count', 1 do
|
||||||
|
assert_difference 'Attachment.count', attachment_count do
|
||||||
|
post :bulk_update, :ids => [3], :copy => '1', :copy_attachments => '1',
|
||||||
|
:issue => {
|
||||||
|
:project_id => ''
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_bulk_copy_to_another_project_should_follow_when_needed
|
def test_bulk_copy_to_another_project_should_follow_when_needed
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
|
post :bulk_update, :ids => [1], :copy => '1', :issue => {:project_id => 2}, :follow => '1'
|
||||||
|
|||||||
@@ -131,6 +131,30 @@ class MessagesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'New body', message.content
|
assert_equal 'New body', message.content
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_post_edit_sticky_and_locked
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
post :edit, :board_id => 1, :id => 1,
|
||||||
|
:message => { :subject => 'New subject',
|
||||||
|
:content => 'New body',
|
||||||
|
:locked => '1',
|
||||||
|
:sticky => '1'}
|
||||||
|
assert_redirected_to '/boards/1/topics/1'
|
||||||
|
message = Message.find(1)
|
||||||
|
assert_equal true, message.sticky?
|
||||||
|
assert_equal true, message.locked?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_post_edit_should_allow_to_change_board
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
post :edit, :board_id => 1, :id => 1,
|
||||||
|
:message => { :subject => 'New subject',
|
||||||
|
:content => 'New body',
|
||||||
|
:board_id => 2}
|
||||||
|
assert_redirected_to '/boards/2/topics/1'
|
||||||
|
message = Message.find(1)
|
||||||
|
assert_equal Board.find(2), message.board
|
||||||
|
end
|
||||||
|
|
||||||
def test_reply
|
def test_reply
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' }
|
post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' }
|
||||||
|
|||||||
@@ -53,4 +53,14 @@ class LayoutTest < ActionController::IntegrationTest
|
|||||||
:attributes => {:src => %r{^/javascripts/jstoolbar/textile.js}},
|
:attributes => {:src => %r{^/javascripts/jstoolbar/textile.js}},
|
||||||
:parent => {:tag => 'head'}
|
:parent => {:tag => 'head'}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_search_field_outside_project_should_link_to_global_search
|
||||||
|
get '/'
|
||||||
|
assert_select 'div#quick-search form[action=/search]'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_search_field_inside_project_should_link_to_project_search
|
||||||
|
get '/projects/ecookbook'
|
||||||
|
assert_select 'div#quick-search form[action=/projects/ecookbook/search]'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -23,5 +23,9 @@ class RoutingSearchTest < ActionController::IntegrationTest
|
|||||||
{ :method => 'get', :path => "/search" },
|
{ :method => 'get', :path => "/search" },
|
||||||
{ :controller => 'search', :action => 'index' }
|
{ :controller => 'search', :action => 'index' }
|
||||||
)
|
)
|
||||||
|
assert_routing(
|
||||||
|
{ :method => 'get', :path => "/projects/foo/search" },
|
||||||
|
{ :controller => 'search', :action => 'index', :id => 'foo' }
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -395,6 +395,14 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
|
assert_equal expected_statuses, issue.new_statuses_allowed_to(admin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_new_statuses_allowed_to_should_return_default_and_current_status_when_copying
|
||||||
|
issue = Issue.find(1).copy
|
||||||
|
assert_equal [1], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
|
||||||
|
|
||||||
|
issue = Issue.find(2).copy
|
||||||
|
assert_equal [1, 2], issue.new_statuses_allowed_to(User.find(2)).map(&:id)
|
||||||
|
end
|
||||||
|
|
||||||
def test_copy
|
def test_copy
|
||||||
issue = Issue.new.copy_from(1)
|
issue = Issue.new.copy_from(1)
|
||||||
assert issue.copy?
|
assert issue.copy?
|
||||||
|
|||||||
@@ -359,6 +359,21 @@ class MailHandlerTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_should_ignore_auto_replied_emails
|
||||||
|
[
|
||||||
|
"X-Auto-Response-Suppress: OOF",
|
||||||
|
"Auto-Submitted: auto-replied",
|
||||||
|
"Auto-Submitted: Auto-Replied"
|
||||||
|
].each do |header|
|
||||||
|
raw = IO.read(File.join(FIXTURES_PATH, 'ticket_on_given_project.eml'))
|
||||||
|
raw = header + "\n" + raw
|
||||||
|
|
||||||
|
assert_no_difference 'Issue.count' do
|
||||||
|
assert_equal false, MailHandler.receive(raw), "email with #{header} header was not ignored"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_add_issue_should_send_email_notification
|
def test_add_issue_should_send_email_notification
|
||||||
Setting.notified_events = ['issue_added']
|
Setting.notified_events = ['issue_added']
|
||||||
ActionMailer::Base.deliveries.clear
|
ActionMailer::Base.deliveries.clear
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ class TimeEntryTest < ActiveSupport::TestCase
|
|||||||
"3 h 15 m" => 3.25,
|
"3 h 15 m" => 3.25,
|
||||||
"3 hours" => 3.0,
|
"3 hours" => 3.0,
|
||||||
"12min" => 0.2,
|
"12min" => 0.2,
|
||||||
|
"12 Min" => 0.2,
|
||||||
}
|
}
|
||||||
|
|
||||||
assertions.each do |k, v|
|
assertions.each do |k, v|
|
||||||
|
|||||||
@@ -630,6 +630,38 @@ class UserTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_default_admin_account_changed_should_return_false_if_account_was_not_changed
|
||||||
|
user = User.find_by_login("admin")
|
||||||
|
user.password = "admin"
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
assert_equal false, User.default_admin_account_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_admin_account_changed_should_return_true_if_password_was_changed
|
||||||
|
user = User.find_by_login("admin")
|
||||||
|
user.password = "newpassword"
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
assert_equal true, User.default_admin_account_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_admin_account_changed_should_return_true_if_account_is_disabled
|
||||||
|
user = User.find_by_login("admin")
|
||||||
|
user.password = "admin"
|
||||||
|
user.status = User::STATUS_LOCKED
|
||||||
|
user.save!
|
||||||
|
|
||||||
|
assert_equal true, User.default_admin_account_changed?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_default_admin_account_changed_should_return_true_if_account_does_not_exist
|
||||||
|
user = User.find_by_login("admin")
|
||||||
|
user.destroy
|
||||||
|
|
||||||
|
assert_equal true, User.default_admin_account_changed?
|
||||||
|
end
|
||||||
|
|
||||||
def test_roles_for_project
|
def test_roles_for_project
|
||||||
# user with a role
|
# user with a role
|
||||||
roles = @jsmith.roles_for_project(Project.find(1))
|
roles = @jsmith.roles_for_project(Project.find(1))
|
||||||
|
|||||||
Reference in New Issue
Block a user