Compare commits

..
1 Commits
Author SHA1 Message Date
Jean-Philippe Lang 7a0e3f40a7 tagged version 2.3.1
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/2.3.1@11759 e93f8b46-1217-0410-a6f0-8f06a7374b81
2013-05-01 15:15:05 +00:00
75 changed files with 216 additions and 608 deletions
+1 -2
View File
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
gem "rails", "3.2.13" gem "rails", "3.2.13"
gem "jquery-rails", "~> 2.0.2" gem "jquery-rails", "~> 2.0.2"
gem "i18n", "~> 0.6.0" gem "i18n", "~> 0.6.0"
gem "coderay", "~> 1.0.9" 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 "builder", "3.0.0" gem "builder", "3.0.0"
@@ -80,7 +80,6 @@ group :test do
gem "shoulda", "~> 3.3.2" gem "shoulda", "~> 3.3.2"
gem "mocha", "~> 0.13.3" gem "mocha", "~> 0.13.3"
gem 'capybara', '~> 2.0.0' gem 'capybara', '~> 2.0.0'
gem 'nokogiri', '< 1.6.0'
end end
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
+7 -5
View File
@@ -70,12 +70,14 @@ class EnumerationsController < ApplicationController
@enumeration.destroy @enumeration.destroy
redirect_to enumerations_path redirect_to enumerations_path
return return
elsif params[:reassign_to_id].present? && (reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id].to_i)) elsif params[:reassign_to_id]
@enumeration.destroy(reassign_to) if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
redirect_to enumerations_path @enumeration.destroy(reassign_to)
return redirect_to enumerations_path
return
end
end end
@enumerations = @enumeration.class.system.all - [@enumeration] @enumerations = @enumeration.class.all - [@enumeration]
end end
private private
+1
View File
@@ -53,6 +53,7 @@ class MyController < ApplicationController
if request.post? if request.post?
@user.safe_attributes = params[:user] @user.safe_attributes = params[:user]
@user.pref.attributes = params[:pref] @user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save if @user.save
@user.pref.save @user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
+2
View File
@@ -92,6 +92,7 @@ class UsersController < ApplicationController
if @user.save if @user.save
@user.pref.attributes = params[:pref] @user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
@user.pref.save @user.pref.save
@user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : [])
@@ -136,6 +137,7 @@ class UsersController < ApplicationController
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE]) was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
# TODO: Similar to My#account # TODO: Similar to My#account
@user.pref.attributes = params[:pref] @user.pref.attributes = params[:pref]
@user.pref[:no_self_notified] = (params[:no_self_notified] == '1')
if @user.save if @user.save
@user.pref.save @user.pref.save
-1
View File
@@ -38,7 +38,6 @@ class Enumeration < ActiveRecord::Base
scope :shared, lambda { where(:project_id => nil) } scope :shared, lambda { where(:project_id => nil) }
scope :sorted, lambda { order("#{table_name}.position ASC") } scope :sorted, lambda { order("#{table_name}.position ASC") }
scope :active, lambda { where(:active => true) } scope :active, lambda { where(:active => true) }
scope :system, lambda { where(:project_id => nil) }
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
def self.default def self.default
+9 -90
View File
@@ -854,99 +854,18 @@ class Issue < ActiveRecord::Base
end end
# Returns all the other issues that depend on the issue # Returns all the other issues that depend on the issue
# The algorithm is a modified breadth first search (bfs)
def all_dependent_issues(except=[]) def all_dependent_issues(except=[])
# The found dependencies except << self
dependencies = [] dependencies = []
dependencies += relations_from.map(&:issue_to)
# The visited flag for every node (issue) used by the breadth first search dependencies += children unless leaf?
eNOT_DISCOVERED = 0 # The issue is "new" to the algorithm, it has not seen it before. dependencies.compact!
ePROCESS_ALL = 1 # The issue is added to the queue. Process both children and relations of
# the issue when it is processed.
ePROCESS_RELATIONS_ONLY = 2 # The issue was added to the queue and will be output as dependent issue,
# but its children will not be added to the queue when it is processed.
eRELATIONS_PROCESSED = 3 # The related issues, the parent issue and the issue itself have been added to
# the queue, but its children have not been added.
ePROCESS_CHILDREN_ONLY = 4 # The relations and the parent of the issue have been added to the queue, but
# the children still need to be processed.
eALL_PROCESSED = 5 # The issue and all its children, its parent and its related issues have been
# added as dependent issues. It needs no further processing.
issue_status = Hash.new(eNOT_DISCOVERED)
# The queue
queue = []
# Initialize the bfs, add start node (self) to the queue
queue << self
issue_status[self] = ePROCESS_ALL
while (!queue.empty?) do
current_issue = queue.shift
current_issue_status = issue_status[current_issue]
dependencies << current_issue
# Add parent to queue, if not already in it.
parent = current_issue.parent
parent_status = issue_status[parent]
if parent && (parent_status == eNOT_DISCOVERED) && !except.include?(parent)
queue << parent
issue_status[parent] = ePROCESS_RELATIONS_ONLY
end
# Add children to queue, but only if they are not already in it and
# the children of the current node need to be processed.
if (current_issue_status == ePROCESS_CHILDREN_ONLY || current_issue_status == ePROCESS_ALL)
current_issue.children.each do |child|
next if except.include?(child)
if (issue_status[child] == eNOT_DISCOVERED)
queue << child
issue_status[child] = ePROCESS_ALL
elsif (issue_status[child] == eRELATIONS_PROCESSED)
queue << child
issue_status[child] = ePROCESS_CHILDREN_ONLY
elsif (issue_status[child] == ePROCESS_RELATIONS_ONLY)
queue << child
issue_status[child] = ePROCESS_ALL
end
end
end
# Add related issues to the queue, if they are not already in it.
current_issue.relations_from.map(&:issue_to).each do |related_issue|
next if except.include?(related_issue)
if (issue_status[related_issue] == eNOT_DISCOVERED)
queue << related_issue
issue_status[related_issue] = ePROCESS_ALL
elsif (issue_status[related_issue] == eRELATIONS_PROCESSED)
queue << related_issue
issue_status[related_issue] = ePROCESS_CHILDREN_ONLY
elsif (issue_status[related_issue] == ePROCESS_RELATIONS_ONLY)
queue << related_issue
issue_status[related_issue] = ePROCESS_ALL
end
end
# Set new status for current issue
if (current_issue_status == ePROCESS_ALL) || (current_issue_status == ePROCESS_CHILDREN_ONLY)
issue_status[current_issue] = eALL_PROCESSED
elsif (current_issue_status == ePROCESS_RELATIONS_ONLY)
issue_status[current_issue] = eRELATIONS_PROCESSED
end
end # while
# Remove the issues from the "except" parameter from the result array
dependencies -= except dependencies -= except
dependencies.delete(self) dependencies += dependencies.map {|issue| issue.all_dependent_issues(except)}.flatten
if parent
dependencies << parent
dependencies += parent.all_dependent_issues(except + parent.descendants)
end
dependencies dependencies
end end
+1 -1
View File
@@ -390,7 +390,7 @@ class Mailer < ActionMailer::Base
# Removes the author from the recipients and cc # Removes the author from the recipients and cc
# if he doesn't want to receive notifications about what he does # if he doesn't want to receive notifications about what he does
if @author && @author.logged? && @author.pref.no_self_notified if @author && @author.logged? && @author.pref[:no_self_notified]
headers[:to].delete(@author.mail) if headers[:to].is_a?(Array) headers[:to].delete(@author.mail) if headers[:to].is_a?(Array)
headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array) headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array)
end end
+1 -4
View File
@@ -673,7 +673,7 @@ class Project < ActiveRecord::Base
# Returns an auto-generated project identifier based on the last identifier used # Returns an auto-generated project identifier based on the last identifier used
def self.next_identifier def self.next_identifier
p = Project.order('id DESC').first p = Project.order('created_on DESC').first
p.nil? ? nil : p.identifier.to_s.succ p.nil? ? nil : p.identifier.to_s.succ
end end
@@ -840,9 +840,6 @@ class Project < ActiveRecord::Base
new_issue = Issue.new new_issue = Issue.new
new_issue.copy_from(issue, :subtasks => false, :link => false) new_issue.copy_from(issue, :subtasks => false, :link => false)
new_issue.project = self new_issue.project = self
# Changing project resets the custom field values
# TODO: handle this in Issue#project=
new_issue.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
# Reassign fixed_versions by name, since names are unique per project # Reassign fixed_versions by name, since names are unique per project
if issue.fixed_version && issue.fixed_version.project == project if issue.fixed_version && issue.fixed_version.project == project
new_issue.fixed_version = self.versions.detect {|v| v.name == issue.fixed_version.name} new_issue.fixed_version = self.versions.detect {|v| v.name == issue.fixed_version.name}
+2 -5
View File
@@ -577,11 +577,8 @@ class Query < ActiveRecord::Base
customized_class = queried_class.reflect_on_association(assoc.to_sym).klass.base_class rescue nil customized_class = queried_class.reflect_on_association(assoc.to_sym).klass.base_class rescue nil
raise "Unknown #{queried_class.name} association #{assoc}" unless customized_class raise "Unknown #{queried_class.name} association #{assoc}" unless customized_class
end end
where = sql_for_field(field, operator, value, db_table, db_field, true) "#{queried_table_name}.#{customized_key} #{not_in} IN (SELECT #{customized_class.table_name}.id FROM #{customized_class.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='#{customized_class}' AND #{db_table}.customized_id=#{customized_class.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " +
if operator =~ /[<>]/ sql_for_field(field, operator, value, db_table, db_field, true) + ')'
where = "(#{where}) AND #{db_table}.#{db_field} <> ''"
end
"#{queried_table_name}.#{customized_key} #{not_in} IN (SELECT #{customized_class.table_name}.id FROM #{customized_class.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='#{customized_class}' AND #{db_table}.customized_id=#{customized_class.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE #{where})"
end end
# Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
+2 -6
View File
@@ -24,15 +24,11 @@ class TimeEntryActivity < Enumeration
OptionName OptionName
end end
def objects
TimeEntry.where(:activity_id => self_and_descendants(1).map(&:id))
end
def objects_count def objects_count
objects.count time_entries.count
end end
def transfer_relations(to) def transfer_relations(to)
objects.update_all(:activity_id => to.id) time_entries.update_all("activity_id = #{to.id}")
end end
end end
-3
View File
@@ -56,7 +56,4 @@ class UserPreference < ActiveRecord::Base
def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end
def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end
def no_self_notified; (self[:no_self_notified] == true || self[:no_self_notified] == '1'); end
def no_self_notified=(value); self[:no_self_notified]=value; end
end end
+1 -2
View File
@@ -47,8 +47,7 @@ class Version < ActiveRecord::Base
'wiki_page_title', 'wiki_page_title',
'status', 'status',
'sharing', 'sharing',
'custom_field_values', 'custom_field_values'
'custom_fields'
# Returns true if +user+ or current user is allowed to view the version # Returns true if +user+ or current user is allowed to view the version
def visible?(user=User.current) def visible?(user=User.current)
+1 -1
View File
@@ -12,7 +12,7 @@
<p><em><%=h @document.category.name %><br /> <p><em><%=h @document.category.name %><br />
<%= format_date @document.created_on %></em></p> <%= format_date @document.created_on %></em></p>
<div class="wiki"> <div class="wiki">
<%= textilizable @document, :description, :attachments => @document.attachments %> <%= textilizable @document.description, :attachments => @document.attachments %>
</div> </div>
<h3><%= l(:label_attachment_plural) %></h3> <h3><%= l(:label_attachment_plural) %></h3>
+1 -1
View File
@@ -4,7 +4,7 @@
<div class="box"> <div class="box">
<p><strong><%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %></strong></p> <p><strong><%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %></strong></p>
<p><label for='reassign_to_id'><%= l(:text_enumeration_category_reassign_to) %></label> <p><label for='reassign_to_id'><%= l(:text_enumeration_category_reassign_to) %></label>
<%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '') + options_from_collection_for_select(@enumerations, 'id', 'name')) %></p> <%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options_from_collection_for_select(@enumerations, 'id', 'name')) %></p>
</div> </div>
<%= submit_tag l(:button_apply) %> <%= submit_tag l(:button_apply) %>
-3
View File
@@ -1,6 +1,3 @@
<% if @journal.private_notes? %>
(<%= l(:field_private_notes) %>)
<% end %>
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> <%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %>
<ul> <ul>
+1 -1
View File
@@ -1,4 +1,4 @@
<%= "(#{l(:field_private_notes)}) " if @journal.private_notes? -%><%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> <%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %>
<% details_to_strings(@journal.details, true).each do |string| -%> <% details_to_strings(@journal.details, true).each do |string| -%>
<%= string %> <%= string %>
+1 -1
View File
@@ -3,7 +3,7 @@ var operatorLabels = <%= raw_json Query.operators_labels %>;
var operatorByType = <%= raw_json Query.operators_by_filter_type %>; var operatorByType = <%= raw_json Query.operators_by_filter_type %>;
var availableFilters = <%= raw_json query.available_filters_as_json %>; var availableFilters = <%= raw_json query.available_filters_as_json %>;
var labelDayPlural = <%= raw_json l(:label_day_plural) %>; var labelDayPlural = <%= raw_json l(:label_day_plural) %>;
var allProjects = <%= raw_json query.all_projects_values %>; var allProjects = <%= raw query.all_projects_values.to_json %>;
$(document).ready(function(){ $(document).ready(function(){
initFilters(); initFilters();
<% query.filters.each do |field, options| %> <% query.filters.each do |field, options| %>
+4 -5
View File
@@ -19,10 +19,9 @@
end %> end %>
<p><em class="info"><%= l(:text_user_mail_option) %></em></p> <p><em class="info"><%= l(:text_user_mail_option) %></em></p>
<% end %> <% end %>
<%= fields_for :pref, @user.pref do |pref_fields| %>
<p> <p>
<%= pref_fields.check_box :no_self_notified %> <label>
<label for="pref_no_self_notified"><%= l(:label_user_mail_no_self_notified) %></label> <%= l(:label_user_mail_no_self_notified) %>
<%= check_box_tag 'no_self_notified', 1, @user.pref[:no_self_notified] %>
</label>
</p> </p>
<% end %>
+2 -2
View File
@@ -50,8 +50,8 @@ ar:
one: "حوالي ساعة" one: "حوالي ساعة"
other: "ساعات %{count}حوالي " other: "ساعات %{count}حوالي "
x_hours: x_hours:
one: "%{count} ساعة" one: "1 hour"
other: "%{count} ساعات" other: "%{count} hours"
x_days: x_days:
one: "يوم" one: "يوم"
other: "%{count} أيام" other: "%{count} أيام"
+2 -2
View File
@@ -109,8 +109,8 @@ az:
many: "təxminən %{count} saat" many: "təxminən %{count} saat"
other: "təxminən %{count} saat" other: "təxminən %{count} saat"
x_hours: x_hours:
one: "1 saat" one: "1 hour"
other: "%{count} saat" other: "%{count} hours"
x_days: x_days:
one: "%{count} gün" one: "%{count} gün"
few: "%{count} gün" few: "%{count} gün"
+2 -2
View File
@@ -51,8 +51,8 @@ bg:
one: "около 1 час" one: "около 1 час"
other: "около %{count} часа" other: "около %{count} часа"
x_hours: x_hours:
one: "1 час" one: "1 hour"
other: "%{count} часа" other: "%{count} hours"
x_days: x_days:
one: "1 ден" one: "1 ден"
other: "%{count} дена" other: "%{count} дена"
+2 -2
View File
@@ -49,8 +49,8 @@ bs:
one: "oko 1 sahat" one: "oko 1 sahat"
other: "oko %{count} sahata" other: "oko %{count} sahata"
x_hours: x_hours:
one: "1 sahat" one: "1 hour"
other: "%{count} sahata" other: "%{count} hours"
x_days: x_days:
one: "1 dan" one: "1 dan"
other: "%{count} dana" other: "%{count} dana"
+2 -2
View File
@@ -53,8 +53,8 @@ ca:
one: "aproximadament 1 hora" one: "aproximadament 1 hora"
other: "aproximadament %{count} hores" other: "aproximadament %{count} hores"
x_hours: x_hours:
one: "1 hora" one: "1 hour"
other: "%{count} hores" other: "%{count} hours"
x_days: x_days:
one: "1 dia" one: "1 dia"
other: "%{count} dies" other: "%{count} dies"
+2 -2
View File
@@ -55,8 +55,8 @@ cs:
one: "asi 1 hodina" one: "asi 1 hodina"
other: "asi %{count} hodin" other: "asi %{count} hodin"
x_hours: x_hours:
one: "1 hodina" one: "1 hour"
other: "%{count} hodin" other: "%{count} hours"
x_days: x_days:
one: "1 den" one: "1 den"
other: "%{count} dnů" other: "%{count} dnů"
+2 -2
View File
@@ -52,8 +52,8 @@ da:
one: "cirka en time" one: "cirka en time"
other: "cirka %{count} timer" other: "cirka %{count} timer"
x_hours: x_hours:
one: "1 time" one: "1 hour"
other: "%{count} timer" other: "%{count} hours"
x_days: x_days:
one: "en dag" one: "en dag"
other: "%{count} dage" other: "%{count} dage"
+2 -2
View File
@@ -53,8 +53,8 @@ de:
one: 'etwa 1 Stunde' one: 'etwa 1 Stunde'
other: 'etwa %{count} Stunden' other: 'etwa %{count} Stunden'
x_hours: x_hours:
one: "1 Stunde" one: "1 hour"
other: "%{count} Stunden" other: "%{count} hours"
x_days: x_days:
one: '1 Tag' one: '1 Tag'
other: '%{count} Tagen' other: '%{count} Tagen'
+2 -2
View File
@@ -52,8 +52,8 @@ el:
one: "περίπου 1 ώρα" one: "περίπου 1 ώρα"
other: "περίπου %{count} ώρες" other: "περίπου %{count} ώρες"
x_hours: x_hours:
one: "1 ώρα" one: "1 hour"
other: "%{count} ώρες" other: "%{count} hours"
x_days: x_days:
one: "1 ημέρα" one: "1 ημέρα"
other: "%{count} ημέρες" other: "%{count} ημέρες"
+2 -2
View File
@@ -80,8 +80,8 @@ es:
one: "alrededor de 1 hora" one: "alrededor de 1 hora"
other: "alrededor de %{count} horas" other: "alrededor de %{count} horas"
x_hours: x_hours:
one: "1 hora" one: "1 hour"
other: "%{count} horas" other: "%{count} hours"
x_days: x_days:
one: "1 día" one: "1 día"
other: "%{count} días" other: "%{count} días"
+2 -2
View File
@@ -67,8 +67,8 @@ et:
one: "umbes tund" one: "umbes tund"
other: "umbes %{count} tundi" other: "umbes %{count} tundi"
x_hours: x_hours:
one: "1 tund" one: "1 hour"
other: "%{count} tundi" other: "%{count} hours"
x_days: x_days:
one: "1 päev" one: "1 päev"
other: "%{count} päeva" other: "%{count} päeva"
+2 -2
View File
@@ -53,8 +53,8 @@ eu:
one: "ordu 1 inguru" one: "ordu 1 inguru"
other: "%{count} ordu inguru" other: "%{count} ordu inguru"
x_hours: x_hours:
one: "ordu 1" one: "1 hour"
other: "%{count} ordu" other: "%{count} hours"
x_days: x_days:
one: "egun 1" one: "egun 1"
other: "%{count} egun" other: "%{count} egun"
+2 -2
View File
@@ -50,8 +50,8 @@ fa:
one: "نزدیک 1 ساعت" one: "نزدیک 1 ساعت"
other: "نزدیک %{count} ساعت" other: "نزدیک %{count} ساعت"
x_hours: x_hours:
one: "1 ساعت" one: "1 hour"
other: "%{count} ساعت" other: "%{count} hours"
x_days: x_days:
one: "1 روز" one: "1 روز"
other: "%{count} روز" other: "%{count} روز"
+2 -2
View File
@@ -95,8 +95,8 @@ fi:
one: "noin tunti" one: "noin tunti"
other: "noin %{count} tuntia" other: "noin %{count} tuntia"
x_hours: x_hours:
one: "1 tunti" one: "1 hour"
other: "%{count} tuntia" other: "%{count} hours"
x_days: x_days:
one: "päivä" one: "päivä"
other: "%{count} päivää" other: "%{count} päivää"
+2 -2
View File
@@ -91,8 +91,8 @@ gl:
one: 'aproximadamente unha hora' one: 'aproximadamente unha hora'
other: '%{count} horas' other: '%{count} horas'
x_hours: x_hours:
one: "1 hora" one: "1 hour"
other: "%{count} horas" other: "%{count} hours"
x_days: x_days:
one: '1 día' one: '1 día'
other: '%{count} días' other: '%{count} días'
+2 -2
View File
@@ -56,8 +56,8 @@ he:
one: 'בערך שעה אחת' one: 'בערך שעה אחת'
other: 'בערך %{count} שעות' other: 'בערך %{count} שעות'
x_hours: x_hours:
one: "1 שעה" one: "1 hour"
other: "%{count} שעות" other: "%{count} hours"
x_days: x_days:
one: 'יום אחד' one: 'יום אחד'
other: '%{count} ימים' other: '%{count} ימים'
+2 -2
View File
@@ -49,8 +49,8 @@ hr:
one: "oko sat vremena" one: "oko sat vremena"
other: "oko %{count} sati" other: "oko %{count} sati"
x_hours: x_hours:
one: "1 sata" one: "1 hour"
other: "%{count} sati" other: "%{count} hours"
x_days: x_days:
one: "1 dan" one: "1 dan"
other: "%{count} dana" other: "%{count} dana"
+2 -2
View File
@@ -51,8 +51,8 @@
one: 'csaknem 1 órája' one: 'csaknem 1 órája'
other: 'csaknem %{count} órája' other: 'csaknem %{count} órája'
x_hours: x_hours:
one: "1 óra" one: "1 hour"
other: "%{count} óra" other: "%{count} hours"
x_days: x_days:
one: '1 napja' one: '1 napja'
other: '%{count} napja' other: '%{count} napja'
+2 -2
View File
@@ -47,8 +47,8 @@ id:
one: "sekitar sejam" one: "sekitar sejam"
other: "sekitar %{count} jam" other: "sekitar %{count} jam"
x_hours: x_hours:
one: "1 jam" one: "1 hour"
other: "%{count} jam" other: "%{count} hours"
x_days: x_days:
one: "sehari" one: "sehari"
other: "%{count} hari" other: "%{count} hari"
+71 -68
View File
@@ -55,8 +55,8 @@ it:
one: "circa un'ora" one: "circa un'ora"
other: "circa %{count} ore" other: "circa %{count} ore"
x_hours: x_hours:
one: "1 ora" one: "1 hour"
other: "%{count} ore" other: "%{count} hours"
x_days: x_days:
one: "1 giorno" one: "1 giorno"
other: "%{count} giorni" other: "%{count} giorni"
@@ -1001,87 +1001,90 @@ it:
button_export: Esporta button_export: Esporta
label_export_options: "%{export_format} opzioni per l'export" label_export_options: "%{export_format} opzioni per l'export"
error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size}) error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size})
notice_failed_to_save_time_entries: "Non ho potuto salvare %{count} registrazioni di tempo impiegato su %{total} selezionate: %{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 segnalazione zero: 0 segnalazione
one: 1 segnalazione one: 1 segnalazione
other: "%{count} segnalazioni" other: "%{count} segnalazioni"
label_repository_new: Nuovo repository label_repository_new: New repository
field_repository_is_default: Repository principale field_repository_is_default: Main repository
label_copy_attachments: Copia allegati label_copy_attachments: Copy attachments
label_item_position: "%{position}/%{count}" label_item_position: "%{position}/%{count}"
label_completed_versions: Completed versions label_completed_versions: Completed versions
text_project_identifier_info: Consentiti solo lettere minuscole (a-z), numeri, trattini e trattini bassi.<br />Una volta salvato, l'identificatore non può essere modificato. text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.
field_multiple: Valori multipli field_multiple: Multiple values
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
text_issue_conflict_resolution_add_notes: Aggiunge le mie note e non salvare le mie ulteriori modifiche text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes
text_issue_conflict_resolution_overwrite: Applica comunque le mie modifiche (le note precedenti verranno mantenute ma alcuni cambiamenti potrebbero essere sovrascritti) text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
notice_issue_update_conflict: La segnalazione è stata aggiornata da un altro utente mentre la stavi editando. notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
text_issue_conflict_resolution_cancel: Cancella ogni modifica e rivisualizza %{link} text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
permission_manage_related_issues: Gestisci relative segnalazioni permission_manage_related_issues: Manage related issues
field_auth_source_ldap_filter: Filtro LDAP field_auth_source_ldap_filter: LDAP filter
label_search_for_watchers: Cerca osservatori da aggiungere label_search_for_watchers: Search for watchers to add
notice_account_deleted: Il tuo account sarà definitivamente rimosso. notice_account_deleted: Your account has been permanently deleted.
setting_unsubscribe: Consentire agli utenti di cancellare il proprio account setting_unsubscribe: Allow users to delete their own account
button_delete_my_account: Cancella il mio account button_delete_my_account: Delete my account
text_account_destroy_confirmation: "Sei sicuro di voler procedere?\nIl tuo account sarà definitivamente cancellato, senza alcuna possibilità di ripristino." text_account_destroy_confirmation: |-
error_session_expired: "La tua sessione è scaduta. Effettua nuovamente il login." Are you sure you want to proceed?
text_session_expiration_settings: "Attenzione: la modifica di queste impostazioni può far scadere le sessioni correnti, compresa la tua." Your account will be permanently deleted, with no way to reactivate it.
setting_session_lifetime: Massima durata di una sessione error_session_expired: Your session has expired. Please login again.
setting_session_timeout: Timeout di inattività di una sessione text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
label_session_expiration: Scadenza sessione setting_session_lifetime: Session maximum lifetime
permission_close_project: Chiusura / riapertura progetto setting_session_timeout: Session inactivity timeout
label_show_closed_projects: Vedi progetti chiusi label_session_expiration: Session expiration
button_close: Chiudi permission_close_project: Close / reopen the project
button_reopen: Riapri label_show_closed_projects: View closed projects
project_status_active: attivo button_close: Close
project_status_closed: chiuso button_reopen: Reopen
project_status_archived: archiviato project_status_active: active
text_project_closed: Questo progetto è chiuso e in sola lettura. project_status_closed: closed
notice_user_successful_create: Creato utente %{id}. project_status_archived: archived
field_core_fields: Campi standard text_project_closed: This project is closed and read-only.
field_timeout: Timeout (in secondi) notice_user_successful_create: User %{id} created.
setting_thumbnails_enabled: Mostra miniature degli allegati field_core_fields: Standard fields
setting_thumbnails_size: Dimensioni delle miniature (in pixels) field_timeout: Timeout (in seconds)
label_status_transitions: Transizioni di stato setting_thumbnails_enabled: Display attachment thumbnails
label_fields_permissions: Permessi sui campi setting_thumbnails_size: Thumbnails size (in pixels)
label_readonly: Sola lettura label_status_transitions: Status transitions
label_required: Richiesto label_fields_permissions: Fields permissions
text_repository_identifier_info: Consentiti solo lettere minuscole (a-z), numeri, trattini e trattini bassi.<br />Una volta salvato, ll'identificatore non può essere modificato. label_readonly: Read-only
label_required: Required
text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.
field_board_parent: Parent forum field_board_parent: Parent forum
label_attribute_of_project: Project's %{name} label_attribute_of_project: Project's %{name}
label_attribute_of_author: Author's %{name} label_attribute_of_author: Author's %{name}
label_attribute_of_assigned_to: Assegnatari %{name} label_attribute_of_assigned_to: Assignee's %{name}
label_attribute_of_fixed_version: Target version's %{name} label_attribute_of_fixed_version: Target version's %{name}
label_copy_subtasks: Copia sottoattività label_copy_subtasks: Copy subtasks
label_copied_to: copia a label_copied_to: copied to
label_copied_from: copia da label_copied_from: copied from
label_any_issues_in_project: ogni segnalazione del progetto label_any_issues_in_project: any issues in project
label_any_issues_not_in_project: ogni segnalazione non nel progetto label_any_issues_not_in_project: any issues not in project
field_private_notes: Note private field_private_notes: Private notes
permission_view_private_notes: Visualizza note private permission_view_private_notes: View private notes
permission_set_notes_private: Imposta note come private permission_set_notes_private: Set notes as private
label_no_issues_in_project: progetto privo di segnalazioni label_no_issues_in_project: no issues in project
label_any: tutti label_any: tutti
label_last_n_weeks: ultime %{count} settimane label_last_n_weeks: last %{count} weeks
setting_cross_project_subtasks: Consenti sottoattività cross-project setting_cross_project_subtasks: Allow cross-project subtasks
label_cross_project_descendants: Con sottoprogetti label_cross_project_descendants: Con sottoprogetti
label_cross_project_tree: Con progetto padre label_cross_project_tree: Con progetto padre
label_cross_project_hierarchy: Con gerarchia progetto label_cross_project_hierarchy: Con gerarchia progetto
label_cross_project_system: Con tutti i progetti label_cross_project_system: Con tutti i progetti
button_hide: Nascondi button_hide: Hide
setting_non_working_week_days: Giorni non lavorativi setting_non_working_week_days: Non-working days
label_in_the_next_days: nei prossimi label_in_the_next_days: in the next
label_in_the_past_days: nei passati label_in_the_past_days: in the past
label_attribute_of_user: Utente %{name} label_attribute_of_user: User's %{name}
text_turning_multiple_off: Disabilitando valori multipli, i valori multipli verranno rimossi, in modo da mantenere un solo valore per item. text_turning_multiple_off: If you disable multiple values, multiple values will be
label_attribute_of_issue: Segnalazione %{name} removed in order to preserve only one value per item.
permission_add_documents: Aggiungi documenti label_attribute_of_issue: Issue's %{name}
permission_edit_documents: Edita documenti permission_add_documents: Add documents
permission_delete_documents: Cancella documenti permission_edit_documents: Edit documents
permission_delete_documents: Delete documents
label_gantt_progress_line: Progress line label_gantt_progress_line: Progress line
setting_jsonp_enabled: Abilita supporto a JSONP setting_jsonp_enabled: Enable JSONP support
field_inherit_members: Eredita membri field_inherit_members: Inherit members
field_closed_on: Chiuso field_closed_on: Closed
setting_default_projects_tracker_ids: Trackers di default per nuovi progetti setting_default_projects_tracker_ids: Default trackers for new projects
label_total_time: Totale label_total_time: Totale
+2 -2
View File
@@ -50,8 +50,8 @@ ko:
one: "약 한시간" one: "약 한시간"
other: "약 %{count}시간" other: "약 %{count}시간"
x_hours: x_hours:
one: "1 시간" one: "1 hour"
other: "%{count} 시간" other: "%{count} hours"
x_days: x_days:
one: "하루" one: "하루"
other: "%{count}일" other: "%{count}일"
+1
View File
@@ -253,6 +253,7 @@ lt:
error_unable_delete_issue_status: 'Negalima ištrinti darbo statuso' error_unable_delete_issue_status: 'Negalima ištrinti darbo statuso'
error_unable_to_connect: Negalima prisijungti (%{value}) error_unable_to_connect: Negalima prisijungti (%{value})
error_attachment_too_big: "Ši byla negali būti įkelta, nes viršija maksimalią (%{max_size}) leistiną bylos apimtį" error_attachment_too_big: "Ši byla negali būti įkelta, nes viršija maksimalią (%{max_size}) leistiną bylos apimtį"
error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})"
warning_attachments_not_saved: "%{count} byla(ų) negali būti išsaugota." warning_attachments_not_saved: "%{count} byla(ų) negali būti išsaugota."
mail_subject_lost_password: "Jūsų %{value} slaptažodis" mail_subject_lost_password: "Jūsų %{value} slaptažodis"
+3 -3
View File
@@ -46,8 +46,8 @@ lv:
one: "aptuveni 1 stunda" one: "aptuveni 1 stunda"
other: "aptuveni %{count} stundas" other: "aptuveni %{count} stundas"
x_hours: x_hours:
one: "1 stunda" one: "1 hour"
other: "%{count} stundas" other: "%{count} hours"
x_days: x_days:
one: "1 diena" one: "1 diena"
other: "%{count} dienas" other: "%{count} dienas"
@@ -775,7 +775,7 @@ lv:
button_cancel: Atcelt button_cancel: Atcelt
button_activate: Aktivizēt button_activate: Aktivizēt
button_sort: Kārtot button_sort: Kārtot
button_log_time: Reģistrēt laiku button_log_time: Ilgs laiks
button_rollback: Atjaunot uz šo versiju button_rollback: Atjaunot uz šo versiju
button_watch: Vērot button_watch: Vērot
button_unwatch: Nevērot button_unwatch: Nevērot
+2 -2
View File
@@ -50,8 +50,8 @@ mk:
one: "околу 1 час" one: "околу 1 час"
other: "околу %{count} часа" other: "околу %{count} часа"
x_hours: x_hours:
one: "1 час" one: "1 hour"
other: "%{count} часа" other: "%{count} hours"
x_days: x_days:
one: "1 ден" one: "1 ден"
other: "%{count} дена" other: "%{count} дена"
+2 -2
View File
@@ -51,8 +51,8 @@ mn:
one: "1 цаг орчим" one: "1 цаг орчим"
other: "ойролцоогоор %{count} цаг" other: "ойролцоогоор %{count} цаг"
x_hours: x_hours:
one: "1 цаг" one: "1 hour"
other: "%{count} цаг" other: "%{count} hours"
x_days: x_days:
one: "1 өдөр" one: "1 өдөр"
other: "%{count} өдөр" other: "%{count} өдөр"
+1 -1
View File
@@ -50,7 +50,7 @@ nl:
other: "ongeveer %{count} uren" other: "ongeveer %{count} uren"
x_hours: x_hours:
one: "1 uur" one: "1 uur"
other: "%{count} uren" other: "%{count} hours"
x_days: x_days:
one: "1 dag" one: "1 dag"
other: "%{count} dagen" other: "%{count} dagen"
+2 -2
View File
@@ -44,8 +44,8 @@
one: "rundt 1 time" one: "rundt 1 time"
other: "rundt %{count} timer" other: "rundt %{count} timer"
x_hours: x_hours:
one: "1 time" one: "1 hour"
other: "%{count} timer" other: "%{count} hours"
x_days: x_days:
one: "1 dag" one: "1 dag"
other: "%{count} dager" other: "%{count} dager"
+3 -3
View File
@@ -82,8 +82,8 @@ pl:
one: "około godziny" one: "około godziny"
other: "około %{count} godzin" other: "około %{count} godzin"
x_hours: x_hours:
one: "1 godzina" one: "1 hour"
other: "%{count} godzin" other: "%{count} hours"
x_days: x_days:
one: "1 dzień" one: "1 dzień"
other: "%{count} dni" other: "%{count} dni"
@@ -772,7 +772,7 @@ pl:
text_default_administrator_account_changed: Zmieniono domyślne hasło administratora text_default_administrator_account_changed: Zmieniono domyślne hasło administratora
text_destroy_time_entries: Usuń wpisy dziennika text_destroy_time_entries: Usuń wpisy dziennika
text_destroy_time_entries_question: Przepracowano %{hours} godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić? text_destroy_time_entries_question: Przepracowano %{hours} godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić?
text_email_delivery_not_configured: "Dostarczanie poczty elektronicznej nie zostało skonfigurowane, więc powiadamianie jest nieaktywne.\nSkonfiguruj serwer SMTP w config/configuration.yml a następnie zrestartuj aplikację i uaktywnij to." text_email_delivery_not_configured: "Dostarczanie poczty elektronicznej nie zostało skonfigurowane, więc powiadamianie jest nieaktywne.\nSkonfiguruj serwer SMTP w config/email.yml a następnie zrestartuj aplikację i uaktywnij to."
text_enumeration_category_reassign_to: 'Zmień przypisanie na tą wartość:' text_enumeration_category_reassign_to: 'Zmień przypisanie na tą wartość:'
text_enumeration_destroy_question: "%{count} obiektów jest przypisanych do tej wartości." text_enumeration_destroy_question: "%{count} obiektów jest przypisanych do tej wartości."
text_file_repository_writable: Zapisywalne repozytorium plików text_file_repository_writable: Zapisywalne repozytorium plików
+1 -1
View File
@@ -1105,5 +1105,5 @@ pt-BR:
setting_jsonp_enabled: Ativar suporte JSONP setting_jsonp_enabled: Ativar suporte JSONP
field_inherit_members: Herdar membros field_inherit_members: Herdar membros
field_closed_on: Fechado field_closed_on: Fechado
setting_default_projects_tracker_ids: Tipos padrões para novos projeto setting_default_projects_tracker_ids: Default trackers for new projects
label_total_time: Total label_total_time: Total
+2 -2
View File
@@ -45,8 +45,8 @@ ro:
one: "aproximativ o oră" one: "aproximativ o oră"
other: "aproximativ %{count} ore" other: "aproximativ %{count} ore"
x_hours: x_hours:
one: "1 oră" one: "1 hour"
other: "%{count} ore" other: "%{count} hours"
x_days: x_days:
one: "o zi" one: "o zi"
other: "%{count} zile" other: "%{count} zile"
+2 -2
View File
@@ -46,8 +46,8 @@ sk:
one: "okolo 1 hodiny" one: "okolo 1 hodiny"
other: "okolo %{count} hodín" other: "okolo %{count} hodín"
x_hours: x_hours:
one: "1 hodina" one: "1 hour"
other: "%{count} hodín" other: "%{count} hours"
x_days: x_days:
one: "1 deň" one: "1 deň"
other: "%{count} dní" other: "%{count} dní"
+2 -2
View File
@@ -50,8 +50,8 @@ sl:
one: "okrog 1. ure" one: "okrog 1. ure"
other: "okrog %{count} ur" other: "okrog %{count} ur"
x_hours: x_hours:
one: "1 ura" one: "1 hour"
other: "%{count} ur" other: "%{count} hours"
x_days: x_days:
one: "1 dan" one: "1 dan"
other: "%{count} dni" other: "%{count} dni"
+2 -2
View File
@@ -50,8 +50,8 @@ sq:
one: "about 1 hour" one: "about 1 hour"
other: "about %{count} hours" other: "about %{count} hours"
x_hours: x_hours:
one: "1 ore" one: "1 hour"
other: "%{count} ore" other: "%{count} hours"
x_days: x_days:
one: "1 day" one: "1 day"
other: "%{count} days" other: "%{count} days"
+2 -2
View File
@@ -53,8 +53,8 @@ sr-YU:
one: "približno jedan sat" one: "približno jedan sat"
other: "približno %{count} sati" other: "približno %{count} sati"
x_hours: x_hours:
one: "1 sat" one: "1 hour"
other: "%{count} sati" other: "%{count} hours"
x_days: x_days:
one: "jedan dan" one: "jedan dan"
other: "%{count} dana" other: "%{count} dana"
+2 -2
View File
@@ -51,8 +51,8 @@ sr:
one: "приближно један сат" one: "приближно један сат"
other: "приближно %{count} сати" other: "приближно %{count} сати"
x_hours: x_hours:
one: "1 сат" one: "1 hour"
other: "%{count} сати" other: "%{count} hours"
x_days: x_days:
one: "један дан" one: "један дан"
other: "%{count} дана" other: "%{count} дана"
+5 -5
View File
@@ -272,7 +272,6 @@ sv:
field_author: Författare field_author: Författare
field_created_on: Skapad field_created_on: Skapad
field_updated_on: Uppdaterad field_updated_on: Uppdaterad
field_closed_on: Stängd
field_field_format: Format field_field_format: Format
field_is_for_all: För alla projekt field_is_for_all: För alla projekt
field_possible_values: Möjliga värden field_possible_values: Möjliga värden
@@ -373,7 +372,6 @@ sv:
field_timeout: "Timeout (i sekunder)" field_timeout: "Timeout (i sekunder)"
field_board_parent: Förälderforum field_board_parent: Förälderforum
field_private_notes: Privata anteckningar field_private_notes: Privata anteckningar
field_inherit_members: Ärv medlemmar
setting_app_title: Applikationsrubrik setting_app_title: Applikationsrubrik
setting_app_subtitle: Applikationsunderrubrik setting_app_subtitle: Applikationsunderrubrik
@@ -442,8 +440,6 @@ sv:
setting_thumbnails_enabled: Visa miniatyrbilder av bilagor setting_thumbnails_enabled: Visa miniatyrbilder av bilagor
setting_thumbnails_size: Storlek på miniatyrbilder (i pixlar) setting_thumbnails_size: Storlek på miniatyrbilder (i pixlar)
setting_non_working_week_days: Lediga dagar setting_non_working_week_days: Lediga dagar
setting_jsonp_enabled: Aktivera JSONP-stöd
setting_default_projects_tracker_ids: Standardärendetyper för nya projekt
permission_add_project: Skapa projekt permission_add_project: Skapa projekt
permission_add_subprojects: Skapa underprojekt permission_add_subprojects: Skapa underprojekt
@@ -661,7 +657,6 @@ sv:
one: 1 ärende one: 1 ärende
other: "%{count} ärenden" other: "%{count} ärenden"
label_total: Total label_total: Total
label_total_time: Total tid
label_permissions: Behörigheter label_permissions: Behörigheter
label_current_status: Nuvarande status label_current_status: Nuvarande status
label_new_statuses_allowed: Nya tillåtna statusvärden label_new_statuses_allowed: Nya tillåtna statusvärden
@@ -1125,3 +1120,8 @@ sv:
description_date_from: Ange startdatum description_date_from: Ange startdatum
description_date_to: Ange slutdatum description_date_to: Ange slutdatum
text_repository_identifier_info: 'Endast gemener (a-z), siffror, streck och understreck är tillåtna.<br />När identifieraren sparats kan den inte ändras.' text_repository_identifier_info: 'Endast gemener (a-z), siffror, streck och understreck är tillåtna.<br />När identifieraren sparats kan den inte ändras.'
setting_jsonp_enabled: Enable JSONP support
field_inherit_members: Inherit members
field_closed_on: Closed
setting_default_projects_tracker_ids: Default trackers for new projects
label_total_time: Total
+2 -2
View File
@@ -56,8 +56,8 @@ tr:
one: 'yaklaşık 1 saat' one: 'yaklaşık 1 saat'
other: 'yaklaşık %{count} saat' other: 'yaklaşık %{count} saat'
x_hours: x_hours:
one: "1 saat" one: "1 hour"
other: "%{count} saat" other: "%{count} hours"
x_days: x_days:
one: '1 gün' one: '1 gün'
other: '%{count} gün' other: '%{count} gün'
+2 -2
View File
@@ -123,8 +123,8 @@
one: "約 1 小時" one: "約 1 小時"
other: "約 %{count} 小時" other: "約 %{count} 小時"
x_hours: x_hours:
one: "1 小時" one: "1 hour"
other: "%{count} 小時" other: "%{count} hours"
x_days: x_days:
one: "1 天" one: "1 天"
other: "%{count} 天" other: "%{count} 天"
+8 -16
View File
@@ -99,11 +99,9 @@ RedmineApp::Application.routes.draw do
match 'copy', :via => [:get, :post] match 'copy', :via => [:get, :post]
end end
shallow do resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do
resources :memberships, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do collection do
collection do get 'autocomplete'
get 'autocomplete'
end
end end
end end
@@ -136,16 +134,12 @@ RedmineApp::Application.routes.draw do
get 'report', :on => :collection get 'report', :on => :collection
end end
resources :queries, :only => [:new, :create] resources :queries, :only => [:new, :create]
shallow do resources :issue_categories, :shallow => true
resources :issue_categories
end
resources :documents, :except => [:show, :edit, :update, :destroy] resources :documents, :except => [:show, :edit, :update, :destroy]
resources :boards resources :boards
shallow do resources :repositories, :shallow => true, :except => [:index, :show] do
resources :repositories, :except => [:index, :show] do member do
member do match 'committers', :via => [:get, :post]
match 'committers', :via => [:get, :post]
end
end end
end end
@@ -182,9 +176,7 @@ RedmineApp::Application.routes.draw do
get 'report' get 'report'
end end
end end
shallow do resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
resources :relations, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy]
end
end end
match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete
-28
View File
@@ -4,34 +4,6 @@ Redmine - project management software
Copyright (C) 2006-2013 Jean-Philippe Lang Copyright (C) 2006-2013 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2013-07-14 v2.3.2
* Defect #9996: configuration.yml in documentation , but redmine ask me to create email.yml
* Defect #13692: warning: already initialized constant on Ruby 1.8.7
* Defect #13783: Internal error on time tracking activity enumeration deletion
* Defect #13821: "obj" parameter is not defined for macros used in description of documents
* Defect #13850: Unable to set custom fields for versions using the REST API
* Defect #13910: Values of custom fields are not kept in issues when copying a project
* Defect #13950: Duplicate Lithuanian "error_attachment_too_big" translation keys
* Defect #14015: Ruby hangs when adding a subtask
* Defect #14020: Locking and unlocking a user resets the email notification checkbox
* Defect #14023: Can't delete relation when Redmine runs in a subpath
* Defect #14051: Filtering issues with custom field in date format with NULL(empty) value
* Defect #14178: PDF API broken in version 2.3.1
* Defect #14186: Project name is not properly escaped in issue filters JSON
* Defect #14242: Project auto generation fails when projects created in the same time
* Defect #14245: Gem::InstallError: nokogiri requires Ruby version >= 1.9.2.
* Defect #14346: Latvian translation for "Log time"
* Feature #12888: Adding markings to emails generated by Private comments
* Feature #14419: Include RUBY_PATCHLEVEL and RUBY_RELEASE_DATE in info.rb
* Patch #14005: Swedish Translation for 2.3-stable
* Patch #14101: Receive IMAP by uid's
* Patch #14103: Disconnect and logout from IMAP after mail receive
* Patch #14145: German translation of x_hours
* Patch #14182: pt-BR translation for 2.3-stable
* Patch #14196: Italian translation for 2.3-stable
* Patch #14221: Translation of x_hours for many languages
== 2013-05-01 v2.3.1 == 2013-05-01 v2.3.1
* Defect #12650: Lost text after selection in issue list with IE * Defect #12650: Lost text after selection in issue list with IE
+3 -6
View File
@@ -394,7 +394,7 @@ module Redmine
# write the cells on page # write the cells on page
issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true) issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width) issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_width)
pdf.SetY(base_y + max_height); pdf.SetY(base_y + max_height);
# rows # rows
@@ -474,7 +474,7 @@ module Redmine
# write the cells on page # write the cells on page
issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width) issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_width)
pdf.SetY(base_y + max_height); pdf.SetY(base_y + max_height);
if query.has_column?(:description) && issue.description? if query.has_column?(:description) && issue.description?
@@ -511,10 +511,7 @@ module Redmine
end end
# Draw lines to close the row (MultiCell border drawing in not uniform) # Draw lines to close the row (MultiCell border drawing in not uniform)
# def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, col_widths)
# parameter "col_id_width" is not used. it is kept for compatibility.
def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
col_id_width, col_widths)
col_x = top_x col_x = top_x
pdf.Line(col_x, top_y, col_x, lower_y) # id right border pdf.Line(col_x, top_y, col_x, lower_y) # id right border
col_widths.each do |width| col_widths.each do |width|
+1 -1
View File
@@ -675,7 +675,7 @@ module Redmine
start_date + (end_date - start_date + 1) * (progress / 100.0) start_date + (end_date - start_date + 1) * (progress / 100.0)
end end
# TODO: Sorts a collection of issues by start_date, due_date, id for gantt rendering # Sorts a collection of issues by start_date, due_date, id for gantt rendering
def sort_issues!(issues) def sort_issues!(issues)
issues.sort! { |a, b| gantt_issue_compare(a, b) } issues.sort! { |a, b| gantt_issue_compare(a, b) }
end end
+10 -12
View File
@@ -29,27 +29,25 @@ module Redmine
imap = Net::IMAP.new(host, port, ssl) imap = Net::IMAP.new(host, port, ssl)
imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil? imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil?
imap.select(folder) imap.select(folder)
imap.uid_search(['NOT', 'SEEN']).each do |uid| imap.search(['NOT', 'SEEN']).each do |message_id|
msg = imap.uid_fetch(uid,'RFC822')[0].attr['RFC822'] msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822']
logger.debug "Receiving message #{uid}" if logger && logger.debug? logger.debug "Receiving message #{message_id}" if logger && logger.debug?
if MailHandler.receive(msg, options) if MailHandler.receive(msg, options)
logger.debug "Message #{uid} successfully received" if logger && logger.debug? logger.debug "Message #{message_id} successfully received" if logger && logger.debug?
if imap_options[:move_on_success] if imap_options[:move_on_success]
imap.uid_copy(uid, imap_options[:move_on_success]) imap.copy(message_id, imap_options[:move_on_success])
end end
imap.uid_store(uid, "+FLAGS", [:Seen, :Deleted]) imap.store(message_id, "+FLAGS", [:Seen, :Deleted])
else else
logger.debug "Message #{uid} can not be processed" if logger && logger.debug? logger.debug "Message #{message_id} can not be processed" if logger && logger.debug?
imap.uid_store(uid, "+FLAGS", [:Seen]) imap.store(message_id, "+FLAGS", [:Seen])
if imap_options[:move_on_failure] if imap_options[:move_on_failure]
imap.uid_copy(uid, imap_options[:move_on_failure]) imap.copy(message_id, imap_options[:move_on_failure])
imap.uid_store(uid, "+FLAGS", [:Deleted]) imap.store(message_id, "+FLAGS", [:Deleted])
end end
end end
end end
imap.expunge imap.expunge
imap.logout
imap.disconnect
end end
private private
+3 -3
View File
@@ -10,16 +10,16 @@ module Redmine
s = "Environment:\n" s = "Environment:\n"
s << [ s << [
["Redmine version", Redmine::VERSION], ["Redmine version", Redmine::VERSION],
["Ruby version", "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"], ["Ruby version", "#{RUBY_VERSION} (#{RUBY_PLATFORM})"],
["Rails version", Rails::VERSION::STRING], ["Rails version", Rails::VERSION::STRING],
["Environment", Rails.env], ["Environment", Rails.env],
["Database adapter", ActiveRecord::Base.connection.adapter_name] ["Database adapter", ActiveRecord::Base.connection.adapter_name]
].map {|info| " %-30s %s" % info}.join("\n") ].map {|info| " %-40s %s" % info}.join("\n")
s << "\nRedmine plugins:\n" s << "\nRedmine plugins:\n"
plugins = Redmine::Plugin.all plugins = Redmine::Plugin.all
if plugins.any? if plugins.any?
s << plugins.map {|plugin| " %-30s %s" % [plugin.id.to_s, plugin.version.to_s]}.join("\n") s << plugins.map {|plugin| " %-40s %s" % [plugin.id.to_s, plugin.version.to_s]}.join("\n")
else else
s << " no plugin installed" s << " no plugin installed"
end end
+1
View File
@@ -33,6 +33,7 @@ module Redmine
module CodeRay module CodeRay
require 'coderay' require 'coderay'
require 'coderay/helpers/file_type'
class << self class << self
# Highlights +text+ as the content of +filename+ # Highlights +text+ as the content of +filename+
+1 -1
View File
@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 2 MAJOR = 2
MINOR = 3 MINOR = 3
TINY = 2 TINY = 1
# Branch values: # Branch values:
# * official release: nil # * official release: nil
+1 -1
View File
@@ -83,7 +83,7 @@ class AdminControllerTest < ActionController::TestCase
def test_test_email def test_test_email
user = User.find(1) user = User.find(1)
user.pref.no_self_notified = '1' user.pref[:no_self_notified] = '1'
user.pref.save! user.pref.save!
ActionMailer::Base.deliveries.clear ActionMailer::Base.deliveries.clear
@@ -126,11 +126,4 @@ class EnumerationsControllerTest < ActionController::TestCase
# check that the issue was reassign # check that the issue was reassign
assert_equal 6, issue.reload.priority_id assert_equal 6, issue.reload.priority_id
end end
def test_destroy_enumeration_in_use_with_blank_reassignment
assert_no_difference 'IssuePriority.count' do
delete :destroy, :id => 4, :reassign_to_id => ''
end
assert_response :success
end
end end
-12
View File
@@ -325,18 +325,6 @@ class UsersControllerTest < ActionController::TestCase
assert_equal [1, 2], u.notified_projects_ids.sort assert_equal [1, 2], u.notified_projects_ids.sort
end end
def test_update_status_should_not_update_attributes
user = User.find(2)
user.pref[:no_self_notified] = '1'
user.pref.save
put :update, :id => 2, :user => {:status => 3}
assert_response 302
user = User.find(2)
assert_equal 3, user.status
assert_equal '1', user.pref[:no_self_notified]
end
def test_destroy def test_destroy
assert_difference 'User.count', -1 do assert_difference 'User.count', -1 do
delete :destroy, :id => 2 delete :destroy, :id => 2
@@ -82,29 +82,6 @@ class Redmine::ApiTest::VersionsTest < Redmine::ApiTest::Base
assert_tag 'version', :child => {:tag => 'id', :content => version.id.to_s} assert_tag 'version', :child => {:tag => 'id', :content => version.id.to_s}
end end
should "create the version with custom fields" do
field = VersionCustomField.generate!
assert_difference 'Version.count' do
post '/projects/1/versions.xml', {
:version => {
:name => 'API test',
:custom_fields => [
{'id' => field.id.to_s, 'value' => 'Some value'}
]
}
}, credentials('jsmith')
end
version = Version.first(:order => 'id DESC')
assert_equal 'API test', version.name
assert_equal 'Some value', version.custom_field_value(field)
assert_response :created
assert_equal 'application/xml', @response.content_type
assert_select 'version>custom_fields>custom_field[id=?]>value', field.id.to_s, 'Some value'
end
context "with failure" do context "with failure" do
should "return the errors" do should "return the errors" do
assert_no_difference('Version.count') do assert_no_difference('Version.count') do
+1 -13
View File
@@ -107,11 +107,10 @@ module ObjectHelpers
def TimeEntry.generate!(attributes={}) def TimeEntry.generate!(attributes={})
entry = TimeEntry.new(attributes) entry = TimeEntry.new(attributes)
entry.user ||= User.find(2) entry.user ||= User.find(2)
entry.issue ||= Issue.find(1) unless entry.project entry.issue ||= Issue.find(1)
entry.project ||= entry.issue.project entry.project ||= entry.issue.project
entry.activity ||= TimeEntryActivity.first entry.activity ||= TimeEntryActivity.first
entry.spent_on ||= Date.today entry.spent_on ||= Date.today
entry.hours ||= 1.0
entry.save! entry.save!
entry entry
end end
@@ -148,15 +147,4 @@ module ObjectHelpers
attachment.save! attachment.save!
attachment attachment
end end
def CustomField.generate!(attributes={})
@generated_custom_field_name ||= 'Custom field 0'
@generated_custom_field_name.succ!
field = new(attributes)
field.name = @generated_custom_field_name.dup if field.name.blank?
field.field_format = 'string' if field.field_format.blank?
yield field if block_given?
field.save!
field
end
end end
@@ -1210,14 +1210,4 @@ RAW
def test_javascript_include_tag_for_plugin_should_pick_the_plugin_javascript def test_javascript_include_tag_for_plugin_should_pick_the_plugin_javascript
assert_match 'src="/plugin_assets/foo/javascripts/scripts.js"', javascript_include_tag("scripts", :plugin => :foo) assert_match 'src="/plugin_assets/foo/javascripts/scripts.js"', javascript_include_tag("scripts", :plugin => :foo)
end end
def test_raw_json_should_escape_closing_tags
s = raw_json(["<foo>bar</foo>"])
assert_equal '["<foo>bar<\/foo>"]', s
end
def test_raw_json_should_be_html_safe
s = raw_json(["foo"])
assert s.html_safe?
end
end end
-130
View File
@@ -1792,136 +1792,6 @@ class IssueTest < ActiveSupport::TestCase
assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
end end
def test_all_dependent_issues_with_subtask
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue = Issue.generate!(:project => project)
childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
assert_equal [childIssue1.id, childIssue2.id].sort, parentIssue.all_dependent_issues.collect(&:id).uniq.sort
end
def test_all_dependent_issues_does_not_include_self
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue = Issue.generate!(:project => project)
childIssue = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
assert_equal [childIssue.id], parentIssue.all_dependent_issues.collect(&:id)
end
def test_all_dependent_issues_with_parenttask_and_sibling
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue = Issue.generate!(:project => project)
childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
assert_equal [parentIssue.id].sort, childIssue1.all_dependent_issues.collect(&:id)
end
def test_all_dependent_issues_with_relation_to_leaf_in_other_tree
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue1 = Issue.generate!(:project => project)
childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
parentIssue2 = Issue.generate!(:project => project)
childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
assert IssueRelation.create(:issue_from => parentIssue1,
:issue_to => childIssue2_2,
:relation_type => IssueRelation::TYPE_BLOCKS)
assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_2.id].sort,
parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
end
def test_all_dependent_issues_with_relation_to_parent_in_other_tree
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue1 = Issue.generate!(:project => project)
childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
parentIssue2 = Issue.generate!(:project => project)
childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
assert IssueRelation.create(:issue_from => parentIssue1,
:issue_to => parentIssue2,
:relation_type => IssueRelation::TYPE_BLOCKS)
assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_1.id, childIssue2_2.id].sort,
parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
end
def test_all_dependent_issues_with_transitive_relation
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue1 = Issue.generate!(:project => project)
childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
parentIssue2 = Issue.generate!(:project => project)
childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
independentIssue = Issue.generate!(:project => project)
assert IssueRelation.create(:issue_from => parentIssue1,
:issue_to => childIssue2_1,
:relation_type => IssueRelation::TYPE_RELATES)
assert IssueRelation.create(:issue_from => childIssue2_1,
:issue_to => independentIssue,
:relation_type => IssueRelation::TYPE_RELATES)
assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
end
def test_all_dependent_issues_with_transitive_relation2
IssueRelation.delete_all
project = Project.generate!(:name => "testproject")
parentIssue1 = Issue.generate!(:project => project)
childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
parentIssue2 = Issue.generate!(:project => project)
childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
independentIssue = Issue.generate!(:project => project)
assert IssueRelation.create(:issue_from => parentIssue1,
:issue_to => independentIssue,
:relation_type => IssueRelation::TYPE_RELATES)
assert IssueRelation.create(:issue_from => independentIssue,
:issue_to => childIssue2_1,
:relation_type => IssueRelation::TYPE_RELATES)
assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
end
def test_all_dependent_issues_with_persistent_circular_dependency def test_all_dependent_issues_with_persistent_circular_dependency
IssueRelation.delete_all IssueRelation.delete_all
assert IssueRelation.create!(:issue_from => Issue.find(1), assert IssueRelation.create!(:issue_from => Issue.find(1),
+3 -14
View File
@@ -215,14 +215,14 @@ class MailerTest < ActiveSupport::TestCase
# Remove members except news author # Remove members except news author
news.project.memberships.each {|m| m.destroy unless m.user == user} news.project.memberships.each {|m| m.destroy unless m.user == user}
user.pref.no_self_notified = false user.pref[:no_self_notified] = false
user.pref.save user.pref.save
User.current = user User.current = user
Mailer.news_added(news.reload).deliver Mailer.news_added(news.reload).deliver
assert_equal 1, last_email.bcc.size assert_equal 1, last_email.bcc.size
# nobody to notify # nobody to notify
user.pref.no_self_notified = true user.pref[:no_self_notified] = true
user.pref.save user.pref.save
User.current = user User.current = user
ActionMailer::Base.deliveries.clear ActionMailer::Base.deliveries.clear
@@ -296,7 +296,7 @@ class MailerTest < ActiveSupport::TestCase
issue = Issue.find(1) issue = Issue.find(1)
user = User.find(9) user = User.find(9)
# minimal email notification options # minimal email notification options
user.pref.no_self_notified = '1' user.pref[:no_self_notified] = '1'
user.pref.save user.pref.save
user.mail_notification = false user.mail_notification = false
user.save user.save
@@ -361,17 +361,6 @@ class MailerTest < ActiveSupport::TestCase
assert_not_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort assert_not_include 'someone@foo.bar', ActionMailer::Base.deliveries.last.bcc.sort
end end
def test_issue_edit_should_mark_private_notes
journal = Journal.find(2)
journal.private_notes = true
journal.save!
with_settings :default_language => 'en' do
Mailer.issue_edit(journal).deliver
end
assert_mail_body_match '(Private notes)', last_email
end
def test_document_added def test_document_added
document = Document.find(1) document = Document.find(1)
valid_languages.each do |lang| valid_languages.each do |lang|
-13
View File
@@ -69,19 +69,6 @@ class ProjectCopyTest < ActiveSupport::TestCase
assert_equal "Closed", copied_issue.status.name assert_equal "Closed", copied_issue.status.name
end end
test "#copy should copy issues custom values" do
field = IssueCustomField.generate!(:is_for_all => true, :trackers => Tracker.all)
issue = Issue.generate!(:project => @source_project, :subject => 'Custom field copy')
issue.custom_field_values = {field.id => 'custom'}
issue.save!
assert_equal 'custom', issue.reload.custom_field_value(field)
assert @project.copy(@source_project)
copy = @project.issues.find_by_subject('Custom field copy')
assert copy
assert_equal 'custom', copy.reload.custom_field_value(field)
end
test "#copy should copy issues assigned to a locked version" do test "#copy should copy issues assigned to a locked version" do
User.current = User.find(1) User.current = User.find(1)
assigned_version = Version.generate!(:name => "Assigned Issues") assigned_version = Version.generate!(:name => "Assigned Issues")
-14
View File
@@ -337,20 +337,6 @@ class QueryTest < ActiveSupport::TestCase
find_issues_with_query(query) find_issues_with_query(query)
end end
def test_operator_lesser_than_on_date_custom_field
f = IssueCustomField.create!(:name => 'filter', :field_format => 'date', :is_filter => true, :is_for_all => true)
CustomValue.create!(:custom_field => f, :customized => Issue.find(1), :value => '2013-04-11')
CustomValue.create!(:custom_field => f, :customized => Issue.find(2), :value => '2013-05-14')
CustomValue.create!(:custom_field => f, :customized => Issue.find(3), :value => '')
query = IssueQuery.new(:project => Project.find(1), :name => '_')
query.add_filter("cf_#{f.id}", '<=', ['2013-05-01'])
issue_ids = find_issues_with_query(query).map(&:id)
assert_include 1, issue_ids
assert_not_include 2, issue_ids
assert_not_include 3, issue_ids
end
def test_operator_between def test_operator_between
query = IssueQuery.new(:project => Project.find(1), :name => '_') query = IssueQuery.new(:project => Project.find(1), :name => '_')
query.add_filter('done_ratio', '><', ['30', '40']) query.add_filter('done_ratio', '><', ['30', '40'])
+1 -29
View File
@@ -84,33 +84,5 @@ class TimeEntryActivityTest < ActiveSupport::TestCase
e.reload e.reload
assert_equal "0", e.custom_value_for(field).value assert_equal "0", e.custom_value_for(field).value
end end
def test_system_activity_with_child_in_use_should_be_in_use
project = Project.generate!
system_activity = TimeEntryActivity.create!(:name => 'Activity')
project_activity = TimeEntryActivity.create!(:name => 'Activity', :project => project, :parent_id => system_activity.id)
TimeEntry.generate!(:project => project, :activity => project_activity)
assert project_activity.in_use?
assert system_activity.in_use?
end
def test_destroying_a_system_activity_should_reassign_children_activities
project = Project.generate!
system_activity = TimeEntryActivity.create!(:name => 'Activity')
project_activity = TimeEntryActivity.create!(:name => 'Activity', :project => project, :parent_id => system_activity.id)
entries = [
TimeEntry.generate!(:project => project, :activity => system_activity),
TimeEntry.generate!(:project => project, :activity => project_activity)
]
assert_difference 'TimeEntryActivity.count', -2 do
assert_nothing_raised do
assert system_activity.destroy(TimeEntryActivity.find_by_name('Development'))
end
end
assert entries.all? {|entry| entry.reload.activity.name == 'Development'}
end
end end