diff -Nru redmine-3.4.2/app/controllers/account_controller.rb redmine-3.4.4/app/controllers/account_controller.rb --- redmine-3.4.2/app/controllers/account_controller.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/controllers/account_controller.rb 2018-01-08 19:37:10.000000000 +0000 @@ -98,7 +98,7 @@ return else if request.post? - email = params[:mail].to_s + email = params[:mail].to_s.strip user = User.find_by_mail(email) # user not found unless user diff -Nru redmine-3.4.2/app/controllers/calendars_controller.rb redmine-3.4.4/app/controllers/calendars_controller.rb --- redmine-3.4.2/app/controllers/calendars_controller.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/controllers/calendars_controller.rb 2018-01-08 19:37:10.000000000 +0000 @@ -39,6 +39,7 @@ @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) retrieve_query @query.group_by = nil + @query.sort_criteria = nil if @query.valid? events = [] events += @query.issues(:include => [:tracker, :assigned_to, :priority], diff -Nru redmine-3.4.2/app/controllers/enumerations_controller.rb redmine-3.4.4/app/controllers/enumerations_controller.rb --- redmine-3.4.2/app/controllers/enumerations_controller.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/controllers/enumerations_controller.rb 2018-01-08 19:37:10.000000000 +0000 @@ -105,6 +105,6 @@ def enumeration_params # can't require enumeration on #new action - params.permit(:enumeration => [:name, :active, :is_default])[:enumeration] + params.permit(:enumeration => [:name, :active, :is_default, :position])[:enumeration] end end diff -Nru redmine-3.4.2/app/controllers/issue_relations_controller.rb redmine-3.4.4/app/controllers/issue_relations_controller.rb --- redmine-3.4.2/app/controllers/issue_relations_controller.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/controllers/issue_relations_controller.rb 2018-01-08 19:37:10.000000000 +0000 @@ -46,7 +46,13 @@ @relation.issue_from = @issue @relation.safe_attributes = params[:relation] @relation.init_journals(User.current) - saved = @relation.save + + begin + saved = @relation.save + rescue ActiveRecord::RecordNotUnique + saved = false + @relation.errors.add :base, :taken + end respond_to do |format| format.html { redirect_to issue_path(@issue) } diff -Nru redmine-3.4.2/app/controllers/wiki_controller.rb redmine-3.4.4/app/controllers/wiki_controller.rb --- redmine-3.4.2/app/controllers/wiki_controller.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/controllers/wiki_controller.rb 2018-01-08 19:37:10.000000000 +0000 @@ -100,14 +100,14 @@ if User.current.allowed_to?(:export_wiki_pages, @project) if params[:format] == 'pdf' - send_file_headers! :type => 'application/pdf', :filename => "#{@page.title}.pdf" + send_file_headers! :type => 'application/pdf', :filename => filename_for_content_disposition("#{@page.title}.pdf") return elsif params[:format] == 'html' export = render_to_string :action => 'export', :layout => false - send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") + send_data(export, :type => 'text/html', :filename => filename_for_content_disposition("#{@page.title}.html")) return elsif params[:format] == 'txt' - send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") + send_data(@content.text, :type => 'text/plain', :filename => filename_for_content_disposition("#{@page.title}.txt")) return end end diff -Nru redmine-3.4.2/app/helpers/application_helper.rb redmine-3.4.4/app/helpers/application_helper.rb --- redmine-3.4.2/app/helpers/application_helper.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/helpers/application_helper.rb 2018-01-08 19:37:10.000000000 +0000 @@ -176,7 +176,8 @@ end case object.class.name when 'Array' - object.map {|o| format_object(o, html)}.join(', ').html_safe + formatted_objects = object.map {|o| format_object(o, html)} + html ? safe_join(formatted_objects, ', ') : formatted_objects.join(', ') when 'Time' format_time(object) when 'Date' @@ -1420,7 +1421,13 @@ elsif user.to_s =~ %r{<(.+?)>} email = $1 end - return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil + if email.present? + gravatar(email.to_s.downcase, options) rescue nil + else + image_tag 'anonymous.png', + GravatarHelper::DEFAULT_OPTIONS + .except(:default, :rating, :ssl).merge(options) + end else '' end diff -Nru redmine-3.4.2/app/helpers/queries_helper.rb redmine-3.4.4/app/helpers/queries_helper.rb --- redmine-3.4.2/app/helpers/queries_helper.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/helpers/queries_helper.rb 2018-01-08 19:37:10.000000000 +0000 @@ -198,7 +198,8 @@ def column_content(column, item) value = column.value_object(item) if value.is_a?(Array) - value.collect {|v| column_value(column, item, v)}.compact.join(', ').html_safe + values = value.collect {|v| column_value(column, item, v)}.compact + safe_join(values, ', ') else column_value(column, item, value) end diff -Nru redmine-3.4.2/app/helpers/repositories_helper.rb redmine-3.4.4/app/helpers/repositories_helper.rb --- redmine-3.4.2/app/helpers/repositories_helper.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/helpers/repositories_helper.rb 2018-01-08 19:37:10.000000000 +0000 @@ -138,7 +138,7 @@ select_tag('repository_scm', options_for_select(scm_options, repository.class.name.demodulize), :disabled => (repository && !repository.new_record?), - :data => {:remote => true, :method => 'get'}) + :data => {:remote => true, :method => 'get', :url => new_project_repository_path(repository.project)}) end def with_leading_slash(path) diff -Nru redmine-3.4.2/app/models/custom_value.rb redmine-3.4.4/app/models/custom_value.rb --- redmine-3.4.2/app/models/custom_value.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/custom_value.rb 2018-01-08 19:37:10.000000000 +0000 @@ -38,12 +38,18 @@ custom_field.editable? end - def visible? - custom_field.visible? + def visible?(user=User.current) + if custom_field.visible? + true + elsif customized.respond_to?(:project) + custom_field.visible_by?(customized.project, user) + else + false + end end def attachments_visible?(user) - visible? && customized && customized.visible?(user) + visible?(user) && customized && customized.visible?(user) end def required? diff -Nru redmine-3.4.2/app/models/issue_query.rb redmine-3.4.4/app/models/issue_query.rb --- redmine-3.4.2/app/models/issue_query.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/issue_query.rb 2018-01-08 19:37:10.000000000 +0000 @@ -187,18 +187,29 @@ @available_columns += issue_custom_fields.visible.collect {|cf| QueryCustomFieldColumn.new(cf) } if User.current.allowed_to?(:view_time_entries, project, :global => true) + # insert the columns after total_estimated_hours or at the end index = @available_columns.find_index {|column| column.name == :total_estimated_hours} index = (index ? index + 1 : -1) - # insert the column after total_estimated_hours or at the end + + subselect = "SELECT SUM(hours) FROM #{TimeEntry.table_name}" + + " JOIN #{Project.table_name} ON #{Project.table_name}.id = #{TimeEntry.table_name}.project_id" + + " WHERE (#{TimeEntry.visible_condition(User.current)}) AND #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" + @available_columns.insert index, QueryColumn.new(:spent_hours, - :sortable => "COALESCE((SELECT SUM(hours) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id), 0)", + :sortable => "COALESCE((#{subselect}), 0)", :default_order => 'desc', :caption => :label_spent_time, :totalable => true ) + + subselect = "SELECT SUM(hours) FROM #{TimeEntry.table_name}" + + " JOIN #{Project.table_name} ON #{Project.table_name}.id = #{TimeEntry.table_name}.project_id" + + " JOIN #{Issue.table_name} subtasks ON subtasks.id = #{TimeEntry.table_name}.issue_id" + + " WHERE (#{TimeEntry.visible_condition(User.current)})" + + " AND subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt" + @available_columns.insert index+1, QueryColumn.new(:total_spent_hours, - :sortable => "COALESCE((SELECT SUM(hours) FROM #{TimeEntry.table_name} JOIN #{Issue.table_name} subtasks ON subtasks.id = #{TimeEntry.table_name}.issue_id" + - " WHERE subtasks.root_id = #{Issue.table_name}.root_id AND subtasks.lft >= #{Issue.table_name}.lft AND subtasks.rgt <= #{Issue.table_name}.rgt), 0)", + :sortable => "COALESCE((#{subselect}), 0)", :default_order => 'desc', :caption => :label_total_spent_time ) @@ -251,15 +262,10 @@ # Returns sum of all the issue's time entries hours def total_for_spent_hours(scope) - total = if group_by_column.try(:name) == :project - # TODO: remove this when https://github.com/rails/rails/issues/21922 is fixed - # We have to do a custom join without the time_entries.project_id column - # that would trigger a ambiguous column name error - scope.joins("JOIN (SELECT issue_id, hours FROM #{TimeEntry.table_name}) AS joined_time_entries ON joined_time_entries.issue_id = #{Issue.table_name}.id"). - sum("joined_time_entries.hours") - else - scope.joins(:time_entries).sum("#{TimeEntry.table_name}.hours") - end + total = scope.joins(:time_entries). + where(TimeEntry.visible_condition(User.current)). + sum("#{TimeEntry.table_name}.hours") + map_total(total) {|t| t.to_f.round(2)} end diff -Nru redmine-3.4.2/app/models/issue.rb redmine-3.4.4/app/models/issue.rb --- redmine-3.4.2/app/models/issue.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/issue.rb 2018-01-08 19:37:10.000000000 +0000 @@ -116,8 +116,6 @@ after_save :after_create_from_copy after_destroy :update_parent_attributes after_create :send_notification - # Keep it at the end of after_save callbacks - after_save :clear_assigned_to_was # Returns a SQL conditions string used to find all issues visible by the specified user def self.visible_condition(user, options={}) @@ -443,7 +441,7 @@ end def estimated_hours=(h) - write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) + write_attribute :estimated_hours, (h.is_a?(String) ? (h.to_hours || h) : h) end safe_attributes 'project_id', diff -Nru redmine-3.4.2/app/models/issue_relation.rb redmine-3.4.4/app/models/issue_relation.rb --- redmine-3.4.2/app/models/issue_relation.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/issue_relation.rb 2018-01-08 19:37:10.000000000 +0000 @@ -204,13 +204,19 @@ # Reverses the relation if needed so that it gets stored in the proper way # Should not be reversed before validation so that it can be displayed back - # as entered on new relation form + # as entered on new relation form. + # + # Orders relates relations by ID, so that uniqueness index in DB is triggered + # on concurrent access. def reverse_if_needed if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] issue_tmp = issue_to self.issue_to = issue_from self.issue_from = issue_tmp self.relation_type = TYPES[relation_type][:reverse] + + elsif relation_type == TYPE_RELATES && issue_from_id > issue_to_id + self.issue_to, self.issue_from = issue_from, issue_to end end @@ -225,6 +231,8 @@ issue_from.blocks? issue_to when 'blocks' issue_to.blocks? issue_from + when 'relates' + self.class.where(issue_from_id: issue_to, issue_to_id: issue_from).present? else false end diff -Nru redmine-3.4.2/app/models/mail_handler.rb redmine-3.4.4/app/models/mail_handler.rb --- redmine-3.4.2/app/models/mail_handler.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/mail_handler.rb 2018-01-08 19:37:10.000000000 +0000 @@ -296,6 +296,7 @@ if email.attachments && email.attachments.any? email.attachments.each do |attachment| next unless accept_attachment?(attachment) + next unless attachment.body.decoded.size > 0 obj.attachments << Attachment.create(:container => obj, :file => attachment.body.decoded, :filename => attachment.filename, diff -Nru redmine-3.4.2/app/models/time_entry_query.rb redmine-3.4.4/app/models/time_entry_query.rb --- redmine-3.4.2/app/models/time_entry_query.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/time_entry_query.rb 2018-01-08 19:37:10.000000000 +0000 @@ -23,7 +23,7 @@ self.available_columns = [ QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), QueryColumn.new(:spent_on, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :default_order => 'desc', :groupable => true), - QueryColumn.new(:tweek, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :caption => l(:label_week)), + QueryColumn.new(:tweek, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :caption => :label_week), QueryColumn.new(:user, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true), QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id"), @@ -35,8 +35,7 @@ def initialize(attributes=nil, *args) super attributes - self.filters ||= {} - add_filter('spent_on', '*') unless filters.present? + self.filters ||= { 'spent_on' => {:operator => "*", :values => []} } end def initialize_available_filters @@ -64,7 +63,7 @@ add_available_filter("issue.fixed_version_id", :type => :list, :name => l("label_attribute_of_issue", :name => l(:field_fixed_version)), - :values => lambda { fixed_version_values }) if project + :values => lambda { fixed_version_values }) add_available_filter("user_id", :type => :list_optional, :values => lambda { author_values } @@ -112,6 +111,13 @@ [['spent_on', 'desc']] end + # If a filter against a single issue is set, returns its id, otherwise nil. + def filtered_issue_id + if value_for('issue_id').to_s =~ /\A(\d+)\z/ + $1 + end + end + def base_scope TimeEntry.visible. joins(:project, :user). @@ -153,7 +159,7 @@ end def sql_for_issue_fixed_version_id_field(field, operator, value) - issue_ids = Issue.where(:fixed_version_id => value.first.to_i).pluck(:id) + issue_ids = Issue.where(:fixed_version_id => value.map(&:to_i)).pluck(:id) case operator when "=" if issue_ids.any? diff -Nru redmine-3.4.2/app/models/user.rb redmine-3.4.4/app/models/user.rb --- redmine-3.4.2/app/models/user.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/models/user.rb 2018-01-08 19:37:10.000000000 +0000 @@ -219,7 +219,7 @@ # Returns the user that matches provided login and password, or nil def self.try_to_login(login, password, active_only=true) - login = login.to_s + login = login.to_s.strip password = password.to_s # Make sure no one can sign in with an empty login or password diff -Nru redmine-3.4.2/app/views/attachments/_form.html.erb redmine-3.4.4/app/views/attachments/_form.html.erb --- redmine-3.4.2/app/views/attachments/_form.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/attachments/_form.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -16,7 +16,7 @@ <%= hidden_field_tag "#{attachment_param}[p#{i}][id]", attachment.id %> <% else %> <%= text_field_tag("#{attachment_param}[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description') if description %> - <%= link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %> + <%= link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'icon-only icon-del remove-upload') %> <%= hidden_field_tag "#{attachment_param}[p#{i}][token]", attachment.token %> <% end %> diff -Nru redmine-3.4.2/app/views/context_menus/issues.html.erb redmine-3.4.4/app/views/context_menus/issues.html.erb --- redmine-3.4.2/app/views/context_menus/issues.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/context_menus/issues.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -39,7 +39,7 @@ diff -Nru redmine-3.4.2/app/views/issues/_form.html.erb redmine-3.4.4/app/views/issues/_form.html.erb --- redmine-3.4.2/app/views/issues/_form.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/issues/_form.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -14,7 +14,7 @@ :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %>

<% end %> -<% if @issue.safe_attribute? 'tracker_id' %> +<% if @issue.safe_attribute?('tracker_id') || (@issue.persisted? && @issue.tracker_id_changed?) %>

<%= f.select :tracker_id, trackers_options_for_select(@issue), {:required => true}, :onchange => "updateIssueFrom('#{escape_javascript update_issue_form_path(@project, @issue)}', this)" %>

<% end %> diff -Nru redmine-3.4.2/app/views/issues/_list.html.erb redmine-3.4.4/app/views/issues/_list.html.erb --- redmine-3.4.2/app/views/issues/_list.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/issues/_list.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -31,7 +31,9 @@ <% end %> "> <%= check_box_tag("ids[]", issue.id, false, :id => nil) %> - <%= raw query.inline_columns.map {|column| "#{column_content(column, issue)}"}.join %> + <% query.inline_columns.each do |column| %> + <%= content_tag('td', column_content(column, issue), :class => column.css_classes) %> + <% end %> <% query.block_columns.each do |column| if (text = column_content(column, issue)) && text.present? -%> diff -Nru redmine-3.4.2/app/views/issues/show.html.erb redmine-3.4.4/app/views/issues/show.html.erb --- redmine-3.4.2/app/views/issues/show.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/issues/show.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -26,8 +26,8 @@ <% end %>
- <%= avatar(@issue.author, :size => "50") %> - <%= avatar(@issue.assigned_to, :size => "22", :class => "gravatar gravatar-child") if @issue.assigned_to %> + <%= avatar(@issue.author, :size => "50", :title => l(:field_author)) %> + <%= avatar(@issue.assigned_to, :size => "22", :class => "gravatar gravatar-child", :title => l(:field_assigned_to)) if @issue.assigned_to %>
diff -Nru redmine-3.4.2/app/views/issues/_watchers_form.html.erb redmine-3.4.4/app/views/issues/_watchers_form.html.erb --- redmine-3.4.2/app/views/issues/_watchers_form.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/issues/_watchers_form.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -1,4 +1,5 @@ <% if @issue.safe_attribute? 'watcher_user_ids' -%> + <%= hidden_field_tag 'issue[watcher_user_ids][]', '' %>

<%= watchers_checkboxes(@issue, users_for_new_issue_watchers(@issue)) %> diff -Nru redmine-3.4.2/app/views/repositories/_revisions.html.erb redmine-3.4.4/app/views/repositories/_revisions.html.erb --- redmine-3.4.2/app/views/repositories/_revisions.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/repositories/_revisions.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -42,7 +42,7 @@ <%= radio_button_tag('rev_to', changeset.identifier, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('#cb-#{line_num}').prop('checked')) {$('#cb-#{line_num-1}').prop('checked',true);}") if show_diff && (line_num > 1) %> <%= format_time(changeset.committed_on) %> <%= changeset.user.blank? ? changeset.author.to_s.truncate(30) : link_to_user(changeset.user) %> -<%= format_changeset_comments changeset, :short => true %> +<%= textilizable(truncate_at_line_break(changeset.comments), :formatting => Setting.commit_logs_formatting?) %> <% line_num += 1 %> <% end %> diff -Nru redmine-3.4.2/app/views/timelog/index.html.erb redmine-3.4.4/app/views/timelog/index.html.erb --- redmine-3.4.2/app/views/timelog/index.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/timelog/index.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -1,6 +1,6 @@

<%= link_to l(:button_log_time), - _new_time_entry_path(@project, @issue), + _new_time_entry_path(@project, @query.filtered_issue_id), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %>
diff -Nru redmine-3.4.2/app/views/timelog/_list.html.erb redmine-3.4.4/app/views/timelog/_list.html.erb --- redmine-3.4.2/app/views/timelog/_list.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/timelog/_list.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -33,7 +33,9 @@ <% end %> hascontextmenu"> <%= check_box_tag("ids[]", entry.id, false, :id => nil) %> - <%= raw @query.inline_columns.map {|column| "#{column_content(column, entry)}"}.join %> + <% @query.inline_columns.each do |column| %> + <%= content_tag('td', column_content(column, entry), :class => column.css_classes) %> + <% end %> <% if entry.editable_by?(User.current) -%> <%= link_to l(:button_edit), edit_time_entry_path(entry), diff -Nru redmine-3.4.2/app/views/versions/_overview.html.erb redmine-3.4.4/app/views/versions/_overview.html.erb --- redmine-3.4.2/app/views/versions/_overview.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/versions/_overview.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -17,9 +17,9 @@ <% if version.issues_count > 0 %> <%= progress_bar([version.closed_percent, version.completed_percent], :titles => - ["%s: %0.0f%" % [l(:label_closed_issues_plural), version.closed_percent], - "%s: %0.0f%" % [l(:field_done_ratio), version.completed_percent]], - :legend => ('%0.0f%' % version.completed_percent)) %> + ["%s: %0.0f%%" % [l(:label_closed_issues_plural), version.closed_percent], + "%s: %0.0f%%" % [l(:field_done_ratio), version.completed_percent]], + :legend => ('%0.0f%%' % version.completed_percent)) %>

<%= link_to(l(:label_x_issues, :count => version.issues_count), version_filtered_issues_path(version, :status_id => '*')) %> diff -Nru redmine-3.4.2/app/views/workflows/_form.html.erb redmine-3.4.4/app/views/workflows/_form.html.erb --- redmine-3.4.2/app/views/workflows/_form.html.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/app/views/workflows/_form.html.erb 2018-01-08 19:37:10.000000000 +0000 @@ -2,7 +2,7 @@ - <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input')", + <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input[type=checkbox]')", :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}", :class => 'icon-only icon-checked') %> <%=l(:label_current_status)%> @@ -13,7 +13,7 @@ <% for new_status in @statuses %> - <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input.new-status-#{new_status.id}')", + <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input[type=checkbox].new-status-#{new_status.id}')", :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}", :class => 'icon-only icon-checked') %> <%= new_status.name %> @@ -26,7 +26,7 @@ <% next if old_status.nil? && name != 'always' %> - <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.try(:id) || 0}')", + <%= link_to_function('', "toggleCheckboxesBySelector('table.transitions-#{name} input[type=checkbox].old-status-#{old_status.try(:id) || 0}')", :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}", :class => 'icon-only icon-checked') %> <% if old_status %> diff -Nru redmine-3.4.2/config/locales/cs.yml redmine-3.4.4/config/locales/cs.yml --- redmine-3.4.2/config/locales/cs.yml 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/config/locales/cs.yml 2018-01-08 19:37:10.000000000 +0000 @@ -1,4 +1,4 @@ -# Update to 2.2, 2.4, 2.5, 2.6, 3.1, 3.3 by Karel Picman +# Update to 2.2, 2.4, 2.5, 2.6, 3.1, 3.3,.. by Karel Picman # Update to 1.1 by Michal Gebauer # Updated by Josef Liška # CZ translation by Maxim Krušina | Massimo Filippi, s.r.o. | maxim@mxm.cz @@ -135,8 +135,8 @@ circular_dependency: "Tento vztah by vytvořil cyklickou závislost" cant_link_an_issue_with_a_descendant: "Úkol nemůže být spojen s jedním z jeho dílčích úkolů" earlier_than_minimum_start_date: "nemůže být dříve než %{date} kvůli předřazeným úkolům" - not_a_regexp: "is not a valid regular expression" - open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task" + not_a_regexp: "není platný regulární výraz" + open_issue_with_closed_parent: "Otevřený úkol nemůže být přiřazen pod uzavřený rodičovský úkol" actionview_instancetag_blank_option: Prosím vyberte @@ -1181,12 +1181,12 @@ mail_body_security_notification_change: ! '%{field} bylo změněno.' mail_body_security_notification_change_to: ! '%{field} bylo změněno na %{value}.' mail_body_security_notification_add: ! '%{field} %{value} bylo přidáno.' - mail_body_security_notification_remove: ! '%{field} %{value} was removed.' + mail_body_security_notification_remove: ! '%{field} %{value} bylo odebráno.' mail_body_security_notification_notify_enabled: Email %{value} nyní dostává notifikace. mail_body_security_notification_notify_disabled: Email %{value} už nedostává notifikace. - mail_body_settings_updated: ! 'The following settings were changed:' + mail_body_settings_updated: ! 'Následující nastavení byla změněna:' field_remote_ip: IP adresa label_wiki_page_new: Nová wiki stránka label_relations: Relace @@ -1205,25 +1205,25 @@ label_font_proportional: Proporciální písmo setting_timespan_format: Formát časového intervalu label_table_of_contents: Obsah - setting_commit_logs_formatting: Apply text formatting to commit messages - setting_mail_handler_enable_regex_delimiters: Enable regular expressions - error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new - project: %{errors}' - error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot - be reassigned to an issue that is about to be deleted - setting_timelog_required_fields: Required fields for time logs - label_attribute_of_object: '%{object_name}''s %{name}' - label_user_mail_option_only_assigned: Only for things I watch or I am assigned to - label_user_mail_option_only_owner: Only for things I watch or I am the owner of - warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion - of values from one or more fields on the selected objects - field_updated_by: Updated by - field_last_updated_by: Last updated by - field_full_width_layout: Full width layout - label_last_notes: Last notes - field_digest: Checksum - field_default_assigned_to: Default assignee - setting_show_custom_fields_on_registration: Show custom fields on registration - permission_view_news: View news - label_no_preview_alternative_html: No preview available. %{link} the file instead. - label_no_preview_download: Download + setting_commit_logs_formatting: Použij textové formátování pro popisky comitů + setting_mail_handler_enable_regex_delimiters: Povol regulární výrazy + error_move_of_child_not_possible: 'Dílčí úkol %{child} nemůže být přesunut do nového + projektu: %{errors}' + error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Strávený čas nemůže + být přiřazen k úkolu, který se bude mazat + setting_timelog_required_fields: Požadovaná pole pro zapisování času + label_attribute_of_object: "%{object_name} %{name}" + label_user_mail_option_only_assigned: Pouze pro věci, které sleduji nebo jsem na ně přiřazený + label_user_mail_option_only_owner: Pouze pro věci, které sleduji nebo jsem jejich vlastníkem + warning_fields_cleared_on_bulk_edit: Změny způsobí automatické smazání + hodnot z jednoho nebo více polí vybraných objektů + field_updated_by: Aktualizoval + field_last_updated_by: Naposledy změnil + field_full_width_layout: Celá šířka schematu + label_last_notes: Poslední poznámky + field_digest: Kontrolní součet + field_default_assigned_to: Výchozí přiřazený uživatel + setting_show_custom_fields_on_registration: Zobraz uživatelská pole při registraci + permission_view_news: Zobraz novinky + label_no_preview_alternative_html: "Náhled není k dispozici. Soubor: %{link}." + label_no_preview_download: Stažení diff -Nru redmine-3.4.2/config/locales/de.yml redmine-3.4.4/config/locales/de.yml --- redmine-3.4.2/config/locales/de.yml 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/config/locales/de.yml 2018-01-08 19:37:10.000000000 +0000 @@ -146,8 +146,8 @@ circular_dependency: "Diese Beziehung würde eine zyklische Abhängigkeit erzeugen" cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einer Ihrer Unteraufgaben verlinkt werden" earlier_than_minimum_start_date: "kann wegen eines Vorgängertickets nicht vor %{date} liegen" - not_a_regexp: "is not a valid regular expression" - open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task" + not_a_regexp: "Ist kein korrekter regulärer Ausdruck" + open_issue_with_closed_parent: "Ein offenes Ticket kann nicht an einen geschlossenen Vater gehängt werden" actionview_instancetag_blank_option: Bitte auswählen @@ -1209,24 +1209,21 @@ setting_new_item_menu_tab: Menü zum Anlegen neuer Objekte label_new_object_tab_enabled: Dropdown-Menü "+" anzeigen label_table_of_contents: Inhaltsverzeichnis - error_no_projects_with_tracker_allowed_for_new_issue: There are no projects with trackers - for which you can create an issue - field_textarea_font: Font used for text areas - label_font_default: Default font - label_font_monospace: Monospaced font - label_font_proportional: Proportional font - setting_commit_logs_formatting: Apply text formatting to commit messages - setting_mail_handler_enable_regex_delimiters: Enable regular expressions - error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot - be reassigned to an issue that is about to be deleted - setting_timelog_required_fields: Required fields for time logs + error_no_projects_with_tracker_allowed_for_new_issue: Es gibt keine Projekte mit Trackern, für welche sie Tickets erzeugen können + field_textarea_font: Schriftart für Textbereiche + label_font_default: Strandardschrift + label_font_monospace: Nichtproporzionale Schrift + label_font_proportional: Proportionale Schrift + setting_commit_logs_formatting: Textformatierung für Commit Nachrichten + setting_mail_handler_enable_regex_delimiters: Reguläre Ausdrücke erlauben + error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Zeitbuchungen für Tickets, die gelöscht werden sind nicht möglich + setting_timelog_required_fields: Erforderliche Felder für Zeitbuchungen label_attribute_of_object: '%{object_name}''s %{name}' - label_user_mail_option_only_assigned: Only for things I watch or I am assigned to - label_user_mail_option_only_owner: Only for things I watch or I am the owner of - warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion - of values from one or more fields on the selected objects - field_updated_by: Updated by - field_last_updated_by: Last updated by - field_full_width_layout: Full width layout - label_last_notes: Last notes - field_digest: Checksum + label_user_mail_option_only_assigned: Nur für Dinge, die ich beobachte oder die mir zugewiesen sind + label_user_mail_option_only_owner: Nur für Dinge, die ich beobachte oder die mir gehören + warning_fields_cleared_on_bulk_edit: Diese Änderungen werden eine automatische Löschung von ein oder mehreren Werten auf den selektierten Objekten zur Folge haben + field_updated_by: Geändert von + field_last_updated_by: Zuletzt geändert von + field_full_width_layout: Layout mit voller Breite + label_last_notes: Letzte Kommentare + field_digest: Checksumme diff -Nru redmine-3.4.2/config/locales/lt.yml redmine-3.4.4/config/locales/lt.yml --- redmine-3.4.2/config/locales/lt.yml 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/config/locales/lt.yml 2018-01-08 19:37:10.000000000 +0000 @@ -4,6 +4,7 @@ # and Gytis Gurklys gytis.gurklys@gmail.com # and Andrius Kriučkovas andrius.kriuckovas@gmail.com # and Gediminas Muižis gediminas.muizis@gmail.com +# and Marius Žilėnas m.zilenas@litrail.lt lt: # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) @@ -134,8 +135,8 @@ circular_dependency: "Šis ryšys sukurtų ciklinę priklausomybę" cant_link_an_issue_with_a_descendant: "Darbas negali būti susietas su viena iš savo darbo dalių" earlier_than_minimum_start_date: "negali būti anksčiau už %{date} dėl ankstesnių darbų" - not_a_regexp: "is not a valid regular expression" - open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task" + not_a_regexp: "neteisingas reguliarusis reiškinys" + open_issue_with_closed_parent: "Atviras darbas negali būti pridėtas prie uždarytos tėvinės užduoties" actionview_instancetag_blank_option: Prašom parinkti @@ -365,7 +366,7 @@ field_time_entries_visibility: Laiko įrašų matomumas field_total_estimated_hours: Visas įsivertinas laikas field_default_version: Numatytoji versija - field_remote_ip: IP address + field_remote_ip: IP adresas setting_app_title: Programos pavadinimas setting_app_subtitle: Programos paantraštė @@ -1176,44 +1177,44 @@ description_issue_category_reassign: Pasirinkti darbo kategoriją description_wiki_subpages_reassign: Pasirinkti naują pagrindinį puslapį text_repository_identifier_info: 'Leidžiamos tik mažosios raidės (a-z), skaitmenys, brūkšneliai ir pabraukimo simboliai.
Kartą išsaugojus pakeitimai negalimi' - label_wiki_page_new: New wiki page - label_relations: Relations - button_filter: Filter - mail_body_password_updated: Your password has been changed. - label_no_preview: No preview available - error_no_tracker_allowed_for_new_issue_in_project: The project doesn't have any trackers - for which you can create an issue - label_tracker_all: All trackers - label_new_project_issue_tab_enabled: Display the "New issue" tab - setting_new_item_menu_tab: Project menu tab for creating new objects - label_new_object_tab_enabled: Display the "+" drop-down - error_no_projects_with_tracker_allowed_for_new_issue: There are no projects with trackers - for which you can create an issue - field_textarea_font: Font used for text areas - label_font_default: Default font - label_font_monospace: Monospaced font - label_font_proportional: Proportional font - setting_timespan_format: Time span format - label_table_of_contents: Table of contents - setting_commit_logs_formatting: Apply text formatting to commit messages - setting_mail_handler_enable_regex_delimiters: Enable regular expressions - error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new - project: %{errors}' - error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot - be reassigned to an issue that is about to be deleted - setting_timelog_required_fields: Required fields for time logs + label_wiki_page_new: Naujas wiki puslapis + label_relations: Ryšiai + button_filter: Filtras + mail_body_password_updated: Slaptažodis pakeistas. + label_no_preview: Peržiūra negalima + error_no_tracker_allowed_for_new_issue_in_project: Projektas neturi jokių pėdsekių, + kuriems galima būtų sukurti darbą + label_tracker_all: Visi pėdsekiai + label_new_project_issue_tab_enabled: Rodyti "Naujo darbo kortelę" + setting_new_item_menu_tab: Projekto meniu ąselė naujų objektų kūrimui + label_new_object_tab_enabled: Rodyti "+" išskleidžiąmąjį sąrašą + error_no_projects_with_tracker_allowed_for_new_issue: Nėra projektų su pėdsekiais, + kuriems galima būtų sukurti darbą + field_textarea_font: Šriftas naudojamas teksto sritims + label_font_default: Numatytasis šriftas + label_font_monospace: Lygiaplotis šriftas + label_font_proportional: Įvairiaplotis šriftas + setting_timespan_format: Laiko tarpo formatas + label_table_of_contents: Turinio lentelė + setting_commit_logs_formatting: Pritaikyti teksto formatavimą patvirtinimo žinutėms + setting_mail_handler_enable_regex_delimiters: Įjungti reguliariuosius reiškinius + error_move_of_child_not_possible: 'Darbo dalis %{child} negali būti perkelta į naują + projektą: %{errors}' + error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Dirbtas laikas negali būti + iš naujo paskirtas darbui, kuris bus ištrintas + setting_timelog_required_fields: Privalomi laukai laiko registracijai label_attribute_of_object: '%{object_name}''s %{name}' - label_user_mail_option_only_assigned: Only for things I watch or I am assigned to - label_user_mail_option_only_owner: Only for things I watch or I am the owner of - warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion - of values from one or more fields on the selected objects - field_updated_by: Updated by - field_last_updated_by: Last updated by - field_full_width_layout: Full width layout - label_last_notes: Last notes - field_digest: Checksum - field_default_assigned_to: Default assignee - setting_show_custom_fields_on_registration: Show custom fields on registration - permission_view_news: View news - label_no_preview_alternative_html: No preview available. %{link} the file instead. - label_no_preview_download: Download + label_user_mail_option_only_assigned: Tik dalykai, kuriuos stebiu arba esu įtrauktas + label_user_mail_option_only_owner: Tik dalykai, kuriuos stebiu arba esu jų savininkas + warning_fields_cleared_on_bulk_edit: Pakeitimai iššauks automatinį reikšmių + pašalinimą iš vieno arba kelių laukų pažymėtiems objektams + field_updated_by: Atnaujino + field_last_updated_by: Paskutinį kartą atnaujino + field_full_width_layout: Viso pločio išdėstymas + label_last_notes: Paskutinės pastabos + field_digest: Kontrolinė suma + field_default_assigned_to: Numatytasis paskirtasis + setting_show_custom_fields_on_registration: Rodyti individualizuotus laukus registracijoje + permission_view_news: Žiūrėti naujienas + label_no_preview_alternative_html: Peržiūra neprieinama. Naudokite failą %{link}. + label_no_preview_download: Atsisiųsti diff -Nru redmine-3.4.2/config/locales/pt-BR.yml redmine-3.4.4/config/locales/pt-BR.yml --- redmine-3.4.2/config/locales/pt-BR.yml 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/config/locales/pt-BR.yml 2018-01-08 19:37:10.000000000 +0000 @@ -148,7 +148,7 @@ greater_than_start_date: "deve ser maior que a data inicial" not_same_project: "não pertence ao mesmo projeto" circular_dependency: "Esta relação geraria uma dependência circular" - cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relaciona a uma de suas subtarefas" + cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relacionada a uma de suas subtarefas" earlier_than_minimum_start_date: "cannot be earlier than %{date} because of preceding issues" not_a_regexp: "is not a valid regular expression" open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task" @@ -250,7 +250,7 @@ field_role: Cargo field_homepage: Página do projeto field_is_public: Público - field_parent: Sub-projeto de + field_parent: Subprojeto de field_is_in_roadmap: Exibir no planejamento field_login: Usuário field_mail_notification: Notificações por e-mail @@ -313,14 +313,14 @@ setting_feeds_limit: Número de registros por Feed setting_default_projects_public: Novos projetos são públicos por padrão setting_autofetch_changesets: Obter commits automaticamente - setting_sys_api_enabled: Ativa WS para gerenciamento do repositório (SVN) + setting_sys_api_enabled: Ativar WS para gerenciamento do repositório (SVN) setting_commit_ref_keywords: Palavras-chave de referência setting_commit_fix_keywords: Definição de palavras-chave setting_autologin: Auto-login setting_date_format: Formato da data setting_time_format: Formato de hora setting_cross_project_issue_relations: Permitir relacionar tarefas entre projetos - setting_issue_list_default_columns: Colunas padrão visíveis na lista de tarefas + setting_issue_list_default_columns: Colunas na lista de tarefas por padrão setting_emails_footer: Rodapé do e-mail setting_protocol: Protocolo setting_per_page_options: Número de itens exibidos por página @@ -422,7 +422,7 @@ label_date: Data label_integer: Inteiro label_float: Decimal - label_boolean: Boleano + label_boolean: Booleano label_string: Texto label_text: Texto longo label_attribute: Atributo @@ -863,7 +863,7 @@ field_sharing: Compartilhamento label_version_sharing_hierarchy: Com a hierarquia do projeto label_version_sharing_system: Com todos os projetos - label_version_sharing_descendants: Com sub-projetos + label_version_sharing_descendants: Com subprojetos label_version_sharing_tree: Com a árvore do projeto label_version_sharing_none: Sem compartilhamento error_can_not_archive_project: Este projeto não pode ser arquivado @@ -885,13 +885,13 @@ permission_view_issues: Ver tarefas label_display_used_statuses_only: Somente exibir situações que são usadas por este tipo de tarefa label_revision_id: Revisão %{value} - label_api_access_key: Chave de acesso a API + label_api_access_key: Chave de acesso à API button_show: Exibir - label_api_access_key_created_on: Chave de acesso a API criado a %{value} atrás + label_api_access_key_created_on: Chave de acesso à API criado há %{value} atrás label_feeds_access_key: Chave de acesso ao Atom - notice_api_access_key_reseted: Sua chave de acesso a API foi redefinida. - setting_rest_api_enabled: Habilitar a api REST - label_missing_api_access_key: Chave de acesso a API faltando + notice_api_access_key_reseted: Sua chave de acesso à API foi redefinida. + setting_rest_api_enabled: Habilitar a API REST + label_missing_api_access_key: Chave de acesso à API faltando label_missing_feeds_access_key: Chave de acesso ao Atom faltando text_line_separated: Múltiplos valores permitidos (uma linha para cada valor). setting_mail_handler_body_delimiters: Truncar e-mails após uma destas linhas @@ -928,7 +928,7 @@ button_edit_associated_wikipage: "Editar página wiki relacionada: %{page_title}" field_text: Campo de texto setting_default_notification_option: Opção padrão de notificação - label_user_mail_option_only_my_events: Somente para as coisas que eu esteja observando ou esteja envolvido + label_user_mail_option_only_my_events: Somente de tarefas que observo ou que esteja envolvido label_user_mail_option_none: Sem eventos field_member_of_group: Responsável pelo grupo field_assigned_to_role: Papel do responsável @@ -1026,7 +1026,7 @@ text_issue_conflict_resolution_cancel: Descartar todas as minhas mudanças e reexibir %{link} permission_manage_related_issues: Gerenciar tarefas relacionadas field_auth_source_ldap_filter: Filtro LDAP - label_search_for_watchers: Procurar por outros observadores para adiconar + label_search_for_watchers: Procurar por outros observadores para adicionar notice_account_deleted: Sua conta foi excluída permanentemente. setting_unsubscribe: Permitir aos usuários excluir sua própria conta button_delete_my_account: Excluir minha conta @@ -1035,8 +1035,8 @@ Sua conta será excluída permanentemente, sem qualquer forma de reativá-la. error_session_expired: A sua sessão expirou. Por favor, faça login novamente. text_session_expiration_settings: "Aviso: a alteração dessas configurações pode expirar as sessões atuais, incluindo a sua." - setting_session_lifetime: duração máxima da sessão - setting_session_timeout: tempo limite de inatividade da sessão + setting_session_lifetime: Duração máxima da sessão + setting_session_timeout: Tempo limite de inatividade da sessão label_session_expiration: "Expiração da sessão" permission_close_project: Fechar / reabrir o projeto label_show_closed_projects: Visualizar projetos fechados @@ -1130,8 +1130,8 @@ label_users_visibility_all: Todos usuários ativos label_users_visibility_members_of_visible_projects: Membros de projetos visíveis label_edit_attachments: Editar arquivos anexados - setting_link_copied_issue: Linkar tarefas copiadas - label_link_copied_issue: Linkar tarefas copiadas + setting_link_copied_issue: Relacionar tarefas copiadas + label_link_copied_issue: Relacionar tarefas copiadas label_ask: Perguntar label_search_attachments_yes: Procurar nome do arquivo e descrição anexados label_search_attachments_no: Não procurar anexados @@ -1162,7 +1162,7 @@ notice_import_finished: "%{count} itens foram importados" notice_import_finished_with_errors: "%{count} fora de %{total} não puderam ser importados" error_invalid_file_encoding: O arquivo não é válido %{encoding} é a codificação do arquivo - error_invalid_csv_file_or_settings: O arquivo não é um arquivo CSV ou não corresponde as + error_invalid_csv_file_or_settings: O arquivo não é um arquivo CSV ou não corresponde às definições abaixo error_can_not_read_import_file: Ocorreu um erro ao ler o arquivo para importação permission_import_issues: Importar tarefas @@ -1176,7 +1176,7 @@ label_quote_char: Citar label_double_quote_char: Citação dupla label_fields_mapping: Mapeamento de campos - label_file_content_preview: Pré-visualir conteúdo do arquivo + label_file_content_preview: Pré-visualizar conteúdo do arquivo label_create_missing_values: Criar valores em falta button_import: Importar field_total_estimated_hours: Tempo estimado geral @@ -1191,7 +1191,7 @@ setting_attachment_extensions_denied: Negar extensões label_any_open_issues: Quaisquer tarefas abertas label_no_open_issues: Sem tarefas abertas - label_default_values_for_new_users: Valor padrão para novos usuários + label_default_values_for_new_users: Valores padrões para novos usuários setting_sys_api_key: Chave de API setting_lost_password: Perdi minha senha mail_subject_security_notification: Notificação de segurança @@ -1216,33 +1216,29 @@ label_new_project_issue_tab_enabled: Exibir "Nova tarefa" em aba setting_new_item_menu_tab: Aba menu do projeto para criação de novos objetos label_new_object_tab_enabled: Exibir o "+" suspenso - error_no_projects_with_tracker_allowed_for_new_issue: There are no projects with trackers - for which you can create an issue - field_textarea_font: Font used for text areas - label_font_default: Default font - label_font_monospace: Monospaced font - label_font_proportional: Proportional font - setting_timespan_format: Time span format - label_table_of_contents: Table of contents - setting_commit_logs_formatting: Apply text formatting to commit messages - setting_mail_handler_enable_regex_delimiters: Enable regular expressions - error_move_of_child_not_possible: 'Subtask %{child} could not be moved to the new - project: %{errors}' - error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: Spent time cannot - be reassigned to an issue that is about to be deleted - setting_timelog_required_fields: Required fields for time logs - label_attribute_of_object: '%{object_name}''s %{name}' - label_user_mail_option_only_assigned: Only for things I watch or I am assigned to - label_user_mail_option_only_owner: Only for things I watch or I am the owner of - warning_fields_cleared_on_bulk_edit: Changes will result in the automatic deletion - of values from one or more fields on the selected objects - field_updated_by: Updated by - field_last_updated_by: Last updated by - field_full_width_layout: Full width layout - label_last_notes: Last notes - field_digest: Checksum - field_default_assigned_to: Default assignee - setting_show_custom_fields_on_registration: Show custom fields on registration - permission_view_news: View news - label_no_preview_alternative_html: No preview available. %{link} the file instead. - label_no_preview_download: Download + error_no_projects_with_tracker_allowed_for_new_issue: Não há projetos com tipos de tarefa para os quais você pode criar uma tarefa + field_textarea_font: Fonte usada para áreas de texto + label_font_default: Fonte padrão + label_font_monospace: Fonte monoespaçada + label_font_proportional: Fonte proporcional + setting_timespan_format: Formato de tempo + label_table_of_contents: Índice + setting_commit_logs_formatting: Aplicar formatação de texto às mensagens de commit + setting_mail_handler_enable_regex_delimiters: Ativar a utilização de expressões regulares + error_move_of_child_not_possible: 'A subtarefa %{child} não pode ser movida para o novo projeto: %{errors}' + error_cannot_reassign_time_entries_to_an_issue_about_to_be_deleted: O tempo gasto não pode ser alterado numa tarefa que será apagada + setting_timelog_required_fields: Campos obrigatórios para registro de horas + label_attribute_of_object: '%{object_name} %{name}' + label_user_mail_option_only_assigned: Somente de tarefas que observo ou que estão atribuídas a mim + label_user_mail_option_only_owner: Somente de tarefas que observo ou que foram criadas por mim + warning_fields_cleared_on_bulk_edit: As alterações vão apagar valores de um ou mais campos nos objetos selecionados + field_updated_by: Atualizado por + field_last_updated_by: Última atualização por + field_full_width_layout: Layout utiliza toda a largura + label_last_notes: Últimas notas + field_digest: Verificador + field_default_assigned_to: Responsável padrão + setting_show_custom_fields_on_registration: Mostrar campos personalizados no registro + permission_view_news: Ver notícias + label_no_preview_alternative_html: Visualização não disponível. Faça o %{link} do arquivo. + label_no_preview_download: download diff -Nru redmine-3.4.2/config/locales/zh.yml redmine-3.4.4/config/locales/zh.yml --- redmine-3.4.2/config/locales/zh.yml 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/config/locales/zh.yml 2018-01-08 19:37:10.000000000 +0000 @@ -134,8 +134,8 @@ circular_dependency: "此关联将导致循环依赖" cant_link_an_issue_with_a_descendant: "问题不能关联到它的子任务" earlier_than_minimum_start_date: "不能早于 %{date} 由于有前置问题" - not_a_regexp: "is not a valid regular expression" - open_issue_with_closed_parent: "An open issue cannot be attached to a closed parent task" + not_a_regexp: "不是一个合法的正则表达式" + open_issue_with_closed_parent: "无法将一个打开的问题关联至一个被关闭的父任务" actionview_instancetag_blank_option: 请选择 @@ -1194,7 +1194,7 @@ error_no_projects_with_tracker_allowed_for_new_issue: 当前项目中不包含对应的跟踪类型,不能创建该类型的工作项。 field_textarea_font: 用于文本区域的字体 label_font_default: 默认字体 - label_font_monospace: 等款字体 + label_font_monospace: 等宽字体 label_font_proportional: 比例字体 setting_timespan_format: 时间格式设置 label_table_of_contents: 目录 diff -Nru redmine-3.4.2/debian/changelog redmine-3.4.4/debian/changelog --- redmine-3.4.2/debian/changelog 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/changelog 2018-04-02 04:52:08.000000000 +0000 @@ -1,3 +1,24 @@ +redmine (3.4.4-1) unstable; urgency=medium + + [ Marc Dequènes (Duck) ] + * New upstream release: + + refreshed patches. + + fix CVE-2017-15568 (Closes: #882544) + + fix CVE-2017-15569 (Closes: #882545) + + fix CVE-2017-15570 (Closes: #882547) + + fix CVE-2017-15571 (Closes: #882548) + + fix CVE-2017-18026 (Closes: #887307) + * Add missing dependency on 'libjs-raphael' (Closes: #857952). + * Updated Russian translation of debconf template, thanks Lev Lamberov + (Closes: #883919) + * Updated VCS URLs (Alioth->Salsa). + + [ Lucas Kanashiro ] + * Bump debhelper compatibility level to 10 + * Declare compliance with Debian Policy 4.1.3 + + -- Marc Dequènes (Duck) Mon, 02 Apr 2018 13:52:08 +0900 + redmine (3.4.2-1) unstable; urgency=medium [ Antonio Terceiro ] diff -Nru redmine-3.4.2/debian/compat redmine-3.4.4/debian/compat --- redmine-3.4.2/debian/compat 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/compat 2018-04-02 04:52:08.000000000 +0000 @@ -1 +1 @@ -9 +10 diff -Nru redmine-3.4.2/debian/control redmine-3.4.4/debian/control --- redmine-3.4.2/debian/control 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/control 2018-04-02 04:52:08.000000000 +0000 @@ -6,7 +6,7 @@ Lucas Kanashiro , Marc Dequènes (Duck) Build-Depends: dbconfig-common, - debhelper (>= 9), + debhelper (>= 10), ruby | ruby-interpreter, ruby-actionpack-action-caching, ruby-actionpack-xml-parser, @@ -29,9 +29,9 @@ ruby-rmagick, ruby-roadie-rails Build-Depends-Indep: po-debconf -Standards-Version: 4.1.0 -Vcs-Browser: https://anonscm.debian.org/cgit/pkg-ruby-extras/redmine.git -Vcs-Git: https://anonscm.debian.org/git/pkg-ruby-extras/redmine.git +Standards-Version: 4.1.3 +Vcs-Browser: https://salsa.debian.org/ruby-team/redmine +Vcs-Git: https://salsa.debian.org/ruby-team/redmine.git Homepage: https://www.redmine.org Package: redmine @@ -60,6 +60,7 @@ ruby-request-store, ruby-rmagick, ruby-roadie-rails, + libjs-raphael, ${misc:Depends} Breaks: redmine-plugin-botsfilter (<=1.02-2), redmine-plugin-recaptcha (<=0.1.0+git20121018) diff -Nru redmine-3.4.2/debian/patches/0001-Gemfile-relax-some-dependencies.patch redmine-3.4.4/debian/patches/0001-Gemfile-relax-some-dependencies.patch --- redmine-3.4.2/debian/patches/0001-Gemfile-relax-some-dependencies.patch 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/patches/0001-Gemfile-relax-some-dependencies.patch 2018-04-02 04:52:08.000000000 +0000 @@ -6,24 +6,24 @@ Gemfile | 50 +++++++++++++++++--------------------------------- 1 file changed, 17 insertions(+), 33 deletions(-) -diff --git a/Gemfile b/Gemfile -index e966d23..5280166 100644 --- a/Gemfile +++ b/Gemfile -@@ -4,37 +4,38 @@ if Gem::Version.new(Bundler::VERSION) < Gem::Version.new('1.5.0') +@@ -4,41 +4,41 @@ abort "Redmine requires Bundler 1.5.0 or higher (you're using #{Bundler::VERSION}).\nPlease update with 'gem update bundler'." end -gem "rails", "4.2.8" +gem "rails", "~> 4.2.8" gem "addressable", "2.4.0" if RUBY_VERSION < "2.0" + if RUBY_VERSION < "2.1" + gem "public_suffix", (RUBY_VERSION < "2.0" ? "~> 1.4" : "~> 2.0.5") + end -gem "jquery-rails", "~> 3.1.4" -gem "coderay", "~> 1.1.1" -gem "request_store", "1.0.5" -gem "mime-types", (RUBY_VERSION >= "2.0" ? "~> 3.0" : "~> 2.99") +gem "jquery-rails", "~> 4.0" +gem "coderay", "~> 1.1" -+gem "builder", ">= 3.0" +gem "request_store", "~> 1.1" +gem "mime-types" gem "protected_attributes" @@ -33,11 +33,11 @@ +gem "roadie-rails", "~> 1.1" +gem "roadie", "~> 3.2" gem "mimemagic" + gem "mail", "~> 2.6.4" --gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.7.2" : "~> 1.6.8") + gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.8.1" : "~> 1.6.8") -gem "i18n", "~> 0.7.0" -gem "ffi", "1.9.14", :platforms => :mingw if RUBY_VERSION < "2.0" -+gem "nokogiri" +gem "i18n", "~> 0.7" +gem "ffi", "1.9", :platforms => :mingw if RUBY_VERSION < "2.0" @@ -46,32 +46,23 @@ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin] --gem "rbpdf", "~> 1.19.2" +-gem "rbpdf", "~> 1.19.3" +gem "rbpdf", "~> 1.19" # Optional gem for LDAP authentication group :ldap do - gem "net-ldap", "~> 0.12.0" -+ gem "net-ldap", "~> 0.8" ++ gem "net-ldap", "~> 0.12" end # Optional gem for OpenID authentication group :openid do - gem "ruby-openid", "~> 2.3.0", :require => "openid" -+ gem "ruby-openid", "~> 2.3", :require => "openid" ++ gem "ruby-openid", "~> 2.7", :require => "openid" gem "rack-openid" end -@@ -46,7 +47,7 @@ platforms :mri, :mingw, :x64_mingw do - - # Optional Markdown support, not for JRuby - group :markdown do -- gem "redcarpet", "~> 3.4.0" -+ gem "redcarpet", "~> 3.4" - end - end - -@@ -62,9 +63,9 @@ if File.exist?(database_file) +@@ -66,9 +66,9 @@ adapters.each do |adapter| case adapter when 'mysql2' @@ -79,11 +70,11 @@ + gem "mysql2", "~> 0.4", :platforms => [:mri, :mingw, :x64_mingw] when /postgresql/ - gem "pg", "~> 0.18.1", :platforms => [:mri, :mingw, :x64_mingw] -+ gem "pg", "~> 0.18", :platforms => [:mri, :mingw, :x64_mingw] ++ gem "pg", "~> 0.19", :platforms => [:mri, :mingw, :x64_mingw] when /sqlite3/ gem "sqlite3", (RUBY_VERSION < "2.0" && RUBY_PLATFORM =~ /mingw/ ? "1.3.12" : "~>1.3.12"), :platforms => [:mri, :mingw, :x64_mingw] -@@ -82,23 +83,6 @@ else +@@ -86,23 +86,6 @@ warn("Please configure your config/database.yml first") end diff -Nru redmine-3.4.2/debian/patches/0004-Add-multi-tenancy-support.patch redmine-3.4.4/debian/patches/0004-Add-multi-tenancy-support.patch --- redmine-3.4.2/debian/patches/0004-Add-multi-tenancy-support.patch 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/patches/0004-Add-multi-tenancy-support.patch 2018-04-02 04:52:08.000000000 +0000 @@ -34,8 +34,6 @@ create mode 100644 config/multitenancy_environment.rb create mode 100644 lib/redmine/multi_tenancy.rb -diff --git a/.gitignore b/.gitignore -index e19e36c..d40280a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,6 +15,7 @@ @@ -46,11 +44,9 @@ /lib/redmine/scm/adapters/mercurial/redminehelper.pyc /lib/redmine/scm/adapters/mercurial/redminehelper.pyo /log/*.log* -diff --git a/Gemfile b/Gemfile -index 5280166..e4fad92 100644 --- a/Gemfile +++ b/Gemfile -@@ -55,12 +55,17 @@ end +@@ -58,12 +58,17 @@ # configuration file require 'erb' require 'yaml' @@ -70,7 +66,7 @@ case adapter when 'mysql2' gem "mysql2", "~> 0.4", :platforms => [:mri, :mingw, :x64_mingw] -@@ -79,8 +84,6 @@ if File.exist?(database_file) +@@ -82,8 +87,6 @@ else warn("No adapter found in config/database.yml, please configure it first") end @@ -79,11 +75,9 @@ end local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") -diff --git a/app/models/attachment.rb b/app/models/attachment.rb -index eea8013..48a3c98 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb -@@ -48,10 +48,10 @@ class Attachment < ActiveRecord::Base +@@ -48,10 +48,10 @@ "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id") cattr_accessor :storage_path @@ -96,9 +90,6 @@ before_create :files_to_final_location after_rollback :delete_from_disk, :on => :create -diff --git a/bin/redmine-instances b/bin/redmine-instances -new file mode 100755 -index 0000000..ab04b47 --- /dev/null +++ b/bin/redmine-instances @@ -0,0 +1,289 @@ @@ -391,11 +382,9 @@ +Street, Fifth Floor, Boston, MA 02110-1301, USA. + +DOCUMENTATION -diff --git a/config/application.rb b/config/application.rb -index e1a416a..8c466f3 100644 --- a/config/application.rb +++ b/config/application.rb -@@ -76,6 +76,7 @@ module RedmineApp +@@ -76,6 +76,7 @@ :key => '_redmine_session', :path => config.relative_url_root || '/' @@ -403,9 +392,6 @@ if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb')) end -diff --git a/config/multitenancy_environment.rb b/config/multitenancy_environment.rb -new file mode 100644 -index 0000000..f3d9248 --- /dev/null +++ b/config/multitenancy_environment.rb @@ -0,0 +1,42 @@ @@ -451,11 +437,9 @@ + end + +end -diff --git a/lib/plugins/open_id_authentication/lib/open_id_authentication.rb b/lib/plugins/open_id_authentication/lib/open_id_authentication.rb -index 48be8dd..1bcbbe4 100644 --- a/lib/plugins/open_id_authentication/lib/open_id_authentication.rb +++ b/lib/plugins/open_id_authentication/lib/open_id_authentication.rb -@@ -25,7 +25,7 @@ module OpenIdAuthentication +@@ -25,7 +25,7 @@ OpenID::Store::Memory.new when :file require 'openid/store/filesystem' @@ -464,11 +448,9 @@ when :memcache require 'memcache' require 'openid/store/memcache' -diff --git a/lib/redmine/configuration.rb b/lib/redmine/configuration.rb -index c9a9b6b..a958fc4 100644 --- a/lib/redmine/configuration.rb +++ b/lib/redmine/configuration.rb -@@ -32,7 +32,7 @@ module Redmine +@@ -32,7 +32,7 @@ # * :file: the configuration file to load (default: config/configuration.yml) # * :env: the environment to load the configuration for (default: Rails.env) def load(options={}) @@ -477,7 +459,7 @@ env = options[:env] || Rails.env @config = @defaults.dup -@@ -104,7 +104,7 @@ module Redmine +@@ -104,7 +104,7 @@ end def load_deprecated_email_configuration(env) @@ -486,11 +468,9 @@ if File.file?(deprecated_email_conf) warn "Storing outgoing emails configuration in config/email.yml is deprecated. You should now store it in config/configuration.yml using the email_delivery setting." @config.merge!({'email_delivery' => load_from_yaml(deprecated_email_conf, env)}) -diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb -index ff383d1..5f596d9 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb -@@ -27,7 +27,7 @@ module Redmine +@@ -27,7 +27,7 @@ attr_accessor :footer_date def initialize(lang, orientation='P') @@ -499,9 +479,6 @@ FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache) set_language_if_valid lang super(orientation, 'mm', 'A4') -diff --git a/lib/redmine/multi_tenancy.rb b/lib/redmine/multi_tenancy.rb -new file mode 100644 -index 0000000..0d100f7 --- /dev/null +++ b/lib/redmine/multi_tenancy.rb @@ -0,0 +1,43 @@ @@ -548,11 +525,9 @@ + end + +end -diff --git a/lib/redmine/plugin.rb b/lib/redmine/plugin.rb -index c3e8c5b..155126e 100644 --- a/lib/redmine/plugin.rb +++ b/lib/redmine/plugin.rb -@@ -47,7 +47,7 @@ module Redmine #:nodoc: +@@ -47,7 +47,7 @@ self.directory = File.join(Rails.root, 'plugins') cattr_accessor :public_directory @@ -561,11 +536,9 @@ @registered_plugins = {} @used_partials = {} -diff --git a/lib/redmine/scm/adapters/abstract_adapter.rb b/lib/redmine/scm/adapters/abstract_adapter.rb -index 437ba92..3cb262a 100644 --- a/lib/redmine/scm/adapters/abstract_adapter.rb +++ b/lib/redmine/scm/adapters/abstract_adapter.rb -@@ -209,7 +209,7 @@ module Redmine +@@ -209,7 +209,7 @@ if @stderr_log_file.nil? writable = false path = Redmine::Configuration['scm_stderr_log_file'].presence @@ -574,11 +547,9 @@ if File.exists?(path) if File.file?(path) && File.writable?(path) writable = true -diff --git a/lib/tasks/initializers.rake b/lib/tasks/initializers.rake -index 6da60c1..eb96177 100644 --- a/lib/tasks/initializers.rake +++ b/lib/tasks/initializers.rake -@@ -15,7 +15,7 @@ file 'config/initializers/secret_token.rb' do +@@ -15,7 +15,7 @@ # change this key, all old sessions will become invalid! Make sure the # secret is at least 30 characters and all random, no regular words or # you'll be exposed to dictionary attacks. diff -Nru redmine-3.4.2/debian/po/ru.po redmine-3.4.4/debian/po/ru.po --- redmine-3.4.2/debian/po/ru.po 2017-11-20 11:33:48.000000000 +0000 +++ redmine-3.4.4/debian/po/ru.po 2018-04-02 04:52:08.000000000 +0000 @@ -3,20 +3,21 @@ # This file is distributed under the same license as the PACKAGE package. # # Yuri Kozlov , 2009, 2010. +# Lev Lamberov , 2017. msgid "" msgstr "" "Project-Id-Version: redmine 1.0.0-4\n" "Report-Msgid-Bugs-To: redmine@packages.debian.org\n" "POT-Creation-Date: 2016-02-15 08:38-0200\n" -"PO-Revision-Date: 2010-08-01 16:37+0400\n" -"Last-Translator: Yuri Kozlov \n" +"PO-Revision-Date: 2017-12-09 15:34+0500\n" +"Last-Translator: Lev Lamberov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Lokalize 1.0\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"X-Generator: Poedit 2.0.4\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. Type: string @@ -50,6 +51,10 @@ "until the package is purged, but they will be no longer managed " "automatically." msgstr "" +"Для отмены настроек экземпляра удалите его идентификатор из данного списка. " +"Файлы настроек и данные из удалённых экземпляров не будут удалены до тех " +"пор, пока этот пакет не будет вычищен. Тем не менее, эти настройки и данные " +"не будут обрабатываться автоматически." #. Type: select #. Description diff -Nru redmine-3.4.2/doc/CHANGELOG redmine-3.4.4/doc/CHANGELOG --- redmine-3.4.2/doc/CHANGELOG 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/doc/CHANGELOG 2018-01-08 19:37:10.000000000 +0000 @@ -4,6 +4,136 @@ Copyright (C) 2006-2017 Jean-Philippe Lang http://www.redmine.org/ +== 2018-01-08 v3.4.4 + +=== [Accounts / authentication] + +* Defect #22532: Strip whitespace from login on login page +* Defect #27754: Strip whitespace from email addresses on lost password page + +=== [Administration] + +* Defect #27586: "Uncheck all" icon at the upper left corner in workflow status transitions page is not working + +=== [Calendar] + +* Defect #27153: Custom query breaks calendar view with error 500 +* Patch #27139: Fix for project link background in calendar tooltips + +=== [Custom fields] + +* Defect #26705: Unable to download file if custom field is not defined as visible to any users + +=== [Email receiving] + +* Patch #27885: Empty email attachments are imported to Redmine, creating broken DB records + +=== [Gantt] + +* Defect #26410: Gravatar icon is misaligned in gantt + +=== [Gems support] + +* Defect #27206: cannot install public_suffix if ruby < 2.1 +* Defect #27505: Cannot install nokogiri 1.7 on Windows Ruby 2.4 + +=== [Issues] + +* Defect #26880: Cannot clear all watchers when copying an issue +* Defect #27110: Changing the tracker to a tracker with the tracker field set to read-only won't work +* Defect #27881: No validation errors when entering an invalid "Estimate hours" value +* Patch #27663: Same relates relation can be created twice +* Patch #27695: Fix ActiveRecord::RecordNotUnique errors when trying to add certain issue relations + +=== [Issues list] + +* Defect #27533: Cannot change the priority of the parent issue in issue query context menu when parent priority is independent of children + +=== [Plugin API] + +* Defect #20513: Unloadable plugin convention breaks with Rails 4.2.3 + +=== [SCM] + +* Defect #27333: Switching SCM fails after validation error in "New repository" page + +=== [Security] + +* Defect #27516: Remote command execution through mercurial adapter + +=== [Translations] + +* Patch #27502: Lithuanian translation for 3.4-stable +* Patch #27620: Brazilian translation update +* Patch #27642: Spanish translation update (jstoolbar-es.js) +* Patch #27649: Spanish/Panama translation update (jstoolbar-es-pa.js) +* Patch #27767: Czech translation for 3.4-stable + +=== [UI] + +* Defect #19578: Issues reports table header overlaping +* Defect #26699: Anonymous user should have their icon + +== 2017-10-15 v3.4.3 + +=== [Administration] + +* Defect #26564: Enumerations sorting does not work + +=== [Custom fields] + +* Defect #26468: Using custom fields of type "File" leads to unsolvable error if filetype is not allowed + +=== [Issues] + +* Defect #26627: Editing issues no longer sends notifications to previous assignee + +=== [Issues list] + +* Defect #26471: Issue Query: inconsistency between spent_hours sum and sum of shown spent_hours values + +=== [PDF export] + +* Defect #25702: Exporting wiki page with specific table to PDF causes 500 + +=== [Roadmap] + +* Patch #26492: % is not valid without a format specifier + +=== [SCM] + +* Defect #26403: The second and subsequent lines of commit messages are not displayed in repository browser +* Defect #26645: git 2.14 compatibility + +=== [Text formatting] + +* Patch #26682: URL-escape the ! character in generated markup for dropped uploads + +=== [Time tracking] + +* Defect #26520: Blank "Issue" field on the "Log time" from the "Spent time - Details" page for an issue +* Defect #26667: Filtering time entries after issue's target version doesn't work as expected in some cases +* Defect #26780: Translation for label_week in time report is not working + +=== [Translations] + +* Patch #26703: German translations in 3.4-stable +* Patch #27034: Patch for updated Chinese translation + +=== [UI] + +* Defect #26568: Multiple Selection List Filter View - items are cut off from view +* Patch #26395: Jump to project autocomplete: focus selected project +* Patch #26689: Add title to author's and assignee's icon + +=== [Wiki] + +* Defect #26599: Corrupted file name when exporting a wiki page with Non-ASCII title using Microsoft's browsers + +=== [Security] + +* Defect #27186: XSS vulnerabilities + == 2017-07-16 v3.4.2 === [Administration] diff -Nru redmine-3.4.2/Gemfile redmine-3.4.4/Gemfile --- redmine-3.4.2/Gemfile 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/Gemfile 2018-01-08 19:37:10.000000000 +0000 @@ -6,6 +6,9 @@ gem "rails", "4.2.8" gem "addressable", "2.4.0" if RUBY_VERSION < "2.0" +if RUBY_VERSION < "2.1" + gem "public_suffix", (RUBY_VERSION < "2.0" ? "~> 1.4" : "~> 2.0.5") +end gem "jquery-rails", "~> 3.1.4" gem "coderay", "~> 1.1.1" gem "request_store", "1.0.5" @@ -15,8 +18,9 @@ gem "roadie-rails", "~> 1.1.1" gem "roadie", "~> 3.2.1" gem "mimemagic" +gem "mail", "~> 2.6.4" -gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.7.2" : "~> 1.6.8") +gem "nokogiri", (RUBY_VERSION >= "2.1" ? "~> 1.8.1" : "~> 1.6.8") gem "i18n", "~> 0.7.0" gem "ffi", "1.9.14", :platforms => :mingw if RUBY_VERSION < "2.0" @@ -25,7 +29,7 @@ # Windows does not include zoneinfo files, so bundle the tzinfo-data gem gem 'tzinfo-data', platforms: [:mingw, :x64_mingw, :mswin] -gem "rbpdf", "~> 1.19.2" +gem "rbpdf", "~> 1.19.3" # Optional gem for LDAP authentication group :ldap do diff -Nru redmine-3.4.2/lib/generators/redmine_plugin_controller/templates/controller.rb.erb redmine-3.4.4/lib/generators/redmine_plugin_controller/templates/controller.rb.erb --- redmine-3.4.2/lib/generators/redmine_plugin_controller/templates/controller.rb.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/generators/redmine_plugin_controller/templates/controller.rb.erb 2018-01-08 19:37:10.000000000 +0000 @@ -1,6 +1,4 @@ class <%= @controller_class %>Controller < ApplicationController - unloadable - <% actions.each do |action| -%> def <%= action %> diff -Nru redmine-3.4.2/lib/generators/redmine_plugin_model/templates/model.rb.erb redmine-3.4.4/lib/generators/redmine_plugin_model/templates/model.rb.erb --- redmine-3.4.2/lib/generators/redmine_plugin_model/templates/model.rb.erb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/generators/redmine_plugin_model/templates/model.rb.erb 2018-01-08 19:37:10.000000000 +0000 @@ -1,3 +1,2 @@ class <%= @model_class %> < ActiveRecord::Base - unloadable end diff -Nru redmine-3.4.2/lib/redmine/helpers/gantt.rb redmine-3.4.4/lib/redmine/helpers/gantt.rb --- redmine-3.4.2/lib/redmine/helpers/gantt.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/redmine/helpers/gantt.rb 2018-01-08 19:37:10.000000000 +0000 @@ -666,7 +666,7 @@ assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name s << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', - :size => 10, + :size => 13, :title => assigned_string).to_s.html_safe end s << view.link_to_issue(issue).html_safe diff -Nru redmine-3.4.2/lib/redmine/scm/adapters/git_adapter.rb redmine-3.4.4/lib/redmine/scm/adapters/git_adapter.rb --- redmine-3.4.2/lib/redmine/scm/adapters/git_adapter.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/redmine/scm/adapters/git_adapter.rb 2018-01-08 19:37:10.000000000 +0000 @@ -54,7 +54,7 @@ end def scm_version_from_command_line - shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s + shellout("#{sq_bin} --version") { |io| io.read }.to_s end end diff -Nru redmine-3.4.2/lib/redmine/scm/adapters/mercurial_adapter.rb redmine-3.4.4/lib/redmine/scm/adapters/mercurial_adapter.rb --- redmine-3.4.2/lib/redmine/scm/adapters/mercurial_adapter.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/redmine/scm/adapters/mercurial_adapter.rb 2018-01-08 19:37:10.000000000 +0000 @@ -32,6 +32,8 @@ # raised if hg command exited with error, e.g. unknown revision. class HgCommandAborted < CommandFailed; end + # raised if bad command argument detected before executing hg. + class HgCommandArgumentError < CommandFailed; end class << self def client_command @@ -138,8 +140,8 @@ def entries(path=nil, identifier=nil, options={}) p1 = scm_iconv(@path_encoding, 'UTF-8', path) - manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), - CGI.escape(without_leading_slash(p1.to_s))) do |io| + manifest = hg('rhmanifest', "-r#{CGI.escape(hgrev(identifier))}", + '--', CGI.escape(without_leading_slash(p1.to_s))) do |io| output = io.read.force_encoding('UTF-8') begin parse_xml(output)['rhmanifest']['repository']['manifest'] @@ -179,10 +181,10 @@ # Iterates the revisions by using a template file that # makes Mercurial produce a xml output. def each_revision(path=nil, identifier_from=nil, identifier_to=nil, options={}) - hg_args = ['log', '--debug', '-C', '--style', self.class.template_path] - hg_args << '-r' << "#{hgrev(identifier_from)}:#{hgrev(identifier_to)}" - hg_args << '--limit' << options[:limit] if options[:limit] - hg_args << hgtarget(path) unless path.blank? + hg_args = ['log', '--debug', '-C', "--style=#{self.class.template_path}"] + hg_args << "-r#{hgrev(identifier_from)}:#{hgrev(identifier_to)}" + hg_args << "--limit=#{options[:limit]}" if options[:limit] + hg_args << '--' << hgtarget(path) unless path.blank? log = hg(*hg_args) do |io| output = io.read.force_encoding('UTF-8') begin @@ -222,23 +224,23 @@ # Returns list of nodes in the specified branch def nodes_in_branch(branch, options={}) - hg_args = ['rhlog', '--template', '{node}\n', '--rhbranch', CGI.escape(branch)] - hg_args << '--from' << CGI.escape(branch) - hg_args << '--to' << '0' - hg_args << '--limit' << options[:limit] if options[:limit] + hg_args = ['rhlog', '--template={node}\n', "--rhbranch=#{CGI.escape(branch)}"] + hg_args << "--from=#{CGI.escape(branch)}" + hg_args << '--to=0' + hg_args << "--limit=#{options[:limit]}" if options[:limit] hg(*hg_args) { |io| io.readlines.map { |e| e.chomp } } end def diff(path, identifier_from, identifier_to=nil) hg_args = %w|rhdiff| if identifier_to - hg_args << '-r' << hgrev(identifier_to) << '-r' << hgrev(identifier_from) + hg_args << "-r#{hgrev(identifier_to)}" << "-r#{hgrev(identifier_from)}" else - hg_args << '-c' << hgrev(identifier_from) + hg_args << "-c#{hgrev(identifier_from)}" end unless path.blank? p = scm_iconv(@path_encoding, 'UTF-8', path) - hg_args << CGI.escape(hgtarget(p)) + hg_args << '--' << CGI.escape(hgtarget(p)) end diff = [] hg *hg_args do |io| @@ -253,7 +255,7 @@ def cat(path, identifier=nil) p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) - hg 'rhcat', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + hg 'rhcat', "-r#{CGI.escape(hgrev(identifier))}", '--', hgtarget(p) do |io| io.binmode io.read end @@ -264,7 +266,7 @@ def annotate(path, identifier=nil) p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) blame = Annotate.new - hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + hg 'rhannotate', '-ncu', "-r#{CGI.escape(hgrev(identifier))}", '--', hgtarget(p) do |io| io.each_line do |line| line.force_encoding('ASCII-8BIT') next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$} @@ -286,10 +288,24 @@ end end + # command options which may be processed earlier, by faulty parser in hg + HG_EARLY_BOOL_ARG = /^--(debugger|profile|traceback)$/ + HG_EARLY_LIST_ARG = /^(--(config|cwd|repo(sitory)?)\b|-R)/ + private_constant :HG_EARLY_BOOL_ARG, :HG_EARLY_LIST_ARG + # Runs 'hg' command with the given args def hg(*args, &block) + # as of hg 4.4.1, early parsing of bool options is not terminated at '--' + if args.any? { |s| s =~ HG_EARLY_BOOL_ARG } + raise HgCommandArgumentError, "malicious command argument detected" + end + if args.take_while { |s| s != '--' }.any? { |s| s =~ HG_EARLY_LIST_ARG } + raise HgCommandArgumentError, "malicious command argument detected" + end + repo_path = root_url || url - full_args = ['-R', repo_path, '--encoding', 'utf-8'] + full_args = ["-R#{repo_path}", '--encoding=utf-8'] + # don't use "--config=" form for compatibility with ancient Mercurial full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}" full_args << '--config' << 'diff.git=false' full_args += args diff -Nru redmine-3.4.2/lib/redmine/version.rb redmine-3.4.4/lib/redmine/version.rb --- redmine-3.4.2/lib/redmine/version.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/lib/redmine/version.rb 2018-01-08 19:37:10.000000000 +0000 @@ -4,7 +4,7 @@ module VERSION #:nodoc: MAJOR = 3 MINOR = 4 - TINY = 2 + TINY = 4 # Branch values: # * official release: nil diff -Nru redmine-3.4.2/public/help/cs/wiki_syntax_detailed_markdown.html redmine-3.4.4/public/help/cs/wiki_syntax_detailed_markdown.html --- redmine-3.4.2/public/help/cs/wiki_syntax_detailed_markdown.html 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/help/cs/wiki_syntax_detailed_markdown.html 2018-01-08 19:37:10.000000000 +0000 @@ -16,7 +16,7 @@

Redmine umožňuje hypertextové odkazy mezi jednotlivými zdroji (úkoly, revize, wiki stránky...) kdekoli, kde je použito Wiki formátování.

Odkazy Wiki:

@@ -30,10 +30,6 @@

Můžete se také odkazovat na Wiki stránky jiného projektu:

+ + + + + + + + + + + + - + + + -

Escaping:

+

Escape sekvence:

-

Externí odkazy

-

URLs (starting with: www, http, https, ftp, ftps, sftp and sftps) and email addresses are automatically turned into clickable links:

+

URL (začínající: www, http, https, ftp, ftps, sftp a sftps) a e-mailové adresy jsou automaticky převedeny na klikací odkazy:

 http://www.redmine.org, someone@foo.bar
@@ -159,7 +162,7 @@
 
         

zobrazí: http://www.redmine.org,

-

Jestliže chcete zobrazit určitý text místo URL, můžete použít standardní syntaxi textile:

+

Jestliže chcete zobrazit určitý text místo URL, můžete použít standardní syntaxi Textile:

 "Webová stránka Redmine":http://www.redmine.org
@@ -168,10 +171,10 @@
         

zobrazí: Webová stránka Redmine

- <

Formátování textu

+

Formátování textu

-

Pro nadpisy, tučný text, tabulky a seznamy, Redmine podporuje syntaxi Textile. Podívejte se na http://en.wikipedia.org/wiki/Textile_(markup_language) pro informace o využití těchto vlastností. Několik příkladů je uvedeno níže, ale Textile toho dokáže mnohem víc.

+

Pro nadpisy, tučný text, tabulky a seznamy, Redmine podporuje syntaxi Markdown. Podívejte se na http://daringfireball.net/projects/markdown/syntax pro informace o využití těchto vlastností. Několik příkladů je uvedeno níže, ale Markdown toho dokáže mnohem víc.

Styly písma

@@ -194,11 +197,11 @@

Vložené obrázky

    -
  • ![](image_url) zobrazí obrázek z odkazu (syntaxe markdown)
  • +
  • ![](image_url) zobrazí obrázek z odkazu (syntaxe Markdown)
  • Jestliže máte obrázek přiložený k Wiki stránce, může být zobrazen jako vložený obrázek pomocí jeho jména: ![](attached_image)
-

Headings

+

Nadpisy

 # Nadpis 1. úrovně
@@ -277,9 +280,9 @@
 
     

Zvýrazňování kódu

-

Výchozí zvýrazňování kódu zavisí na CodeRay, což je rychlá zvýrazňovací knihovna napsaná v Ruby. It currently supports c, clojure, cpp (c++, cplusplus), css, delphi (pascal), diff (patch), erb (eruby, rhtml), go, groovy, haml, html (xhtml), java, javascript (ecmascript, ecma_script, java_script, js), json, lua, php, python, ruby (irb), sass, sql, taskpaper, text (plain, plaintext), xml and yaml (yml) languages, where the names inside parentheses are aliases.

+

Výchozí zvýrazňování kódu zavisí na CodeRay, což je rychlá zvýrazňovací knihovna napsaná v Ruby. Aktuálně podporuje: c, clojure, cpp (c++, cplusplus), css, delphi (pascal), diff (patch), erb (eruby, rhtml), go, groovy, haml, html (xhtml), java, javascript (ecmascript, ecma_script, java_script, js), json, lua, php, python, ruby (irb), sass, sql, taskpaper, text (plain, plaintext), xml a yaml (yml) jazyky, jejichž jména jsou v závorkách jsou aliasy.

-

Kód můžete na stránce zvýraznit pomocí následující syntaxe (note that the language name or alias is case-insensitive):

+

Kód můžete na stránce zvýraznit pomocí následující syntaxe (záleží na velikosti písma jazyku nebo aliasu):

 ~~~ ruby
diff -Nru redmine-3.4.2/public/help/cs/wiki_syntax_detailed_textile.html redmine-3.4.4/public/help/cs/wiki_syntax_detailed_textile.html
--- redmine-3.4.2/public/help/cs/wiki_syntax_detailed_textile.html	2017-07-16 18:19:12.000000000 +0000
+++ redmine-3.4.4/public/help/cs/wiki_syntax_detailed_textile.html	2018-01-08 19:37:10.000000000 +0000
@@ -45,7 +45,8 @@
                     
  • document:Úvod (odkaz na dokument s názvem "Úvod")
  • document:"Nějaký dokument" (Uvozovky se mohou použít v případě, že název obsahuje mezery.)
  • projekt_test:document:"Nějaký dokument" (odkaz na dokument s názvem "Nějaký dokument" v jiném projektu "projekt_test")
  • - + +
      @@ -55,7 +56,8 @@
    • version:1.0.0 odkaz na verzi s názvem "1.0.0")
    • version:"1.0 beta 2"
    • projekt_test:version:1.0.0 (odkaz na verzi "1.0.0" jiného projektu "projekt_test")
    • -
    + +
      @@ -63,7 +65,8 @@
      • attachment:soubor.zip (odkaz na přílohu aktuálního objektu s názvem soubor.zip)
      • Aktuálně mohou být odkazovány pouze přílohy aktuálního objektu (u úkolu mohou být odkazy pouze na přílohy danného úkolu).
      • -
      +
    +
      @@ -75,7 +78,8 @@
    • commit:hg|c6f4d0fd (odkaz na revizi s nečíselným označním revize určitého repozitáře, pro projekty s více repozitáři)
    • projekt_test:r758 (odkaz na revizi jiného projektu)
    • projekt_test:commit:c6f4d0fd (odkaz na revizi s nečíselným označním revize jiného projektu)
    • -
    + +
      @@ -90,7 +94,8 @@
    • source:svn1|some/file (odkaz na soubor určitého repozitáře, pro projekty s více repositáři)
    • projekt_test:source:some/file (odkaz na soubor umístěný v /some/file repositáře projektu "projekt_test")
    • projekt_test:export:some/file (vynutit stažení souboru umístěného v /some/file repositáře projektu "projekt_test")
    • -
    + +
      @@ -99,14 +104,16 @@
    • forum#1 (odkaz na fórum s id 1
    • forum:Support (odkaz na fórum pojmenované Support)
    • forum:"Technical Support" (Použij dvojté uvozovkym jestliže název fóra obsahuje mezery.)
    • -
    + +
    • Příspěvky diskuzního fóra:
      • message#1218 (odkaz na příspěvek s ID 1218)
      • -
    • +
    +
      @@ -115,7 +122,8 @@
    • project#3 (odkaz na projekt s ID 3)
    • project:projekt_test (odkaz na projekt pojmenovaný "projekt_test")
    • project:"projekt test" (odkaz na projekt pojmenovaný "projekt test")
    • -
    + +
      @@ -124,20 +132,21 @@
    • news#2 (odkaz na novinku id 2)
    • news:Greetings (odkaz na novinku "Greetings")
    • news:"First Release" (použij dvojté uvozovky, jestliže název novinky obsahuje mezery)
    • -
    + +
      -
    • Users: +
    • Uživatelé:
        -
      • user#2 (link to user with id 2)
      • -
      • user:jsmith (Link to user with login jsmith)
      • -
      • @jsmith (Link to user with login jsmith)
      • +
      • user#2 (odkaz na uživatele s id 2)
      • +
      • user:jsmith (odkaz na uživatele s loginem jsmith)
      • +
      • @jsmith (odkaz na uživatele s loginem jsmith)
    -

    Escaping:

    +

    Escape sekvence:

    • Zabránit parsování Redmine odkazů, lze vložením vykřičníku před odkaz: !
    • @@ -146,7 +155,7 @@

      Externí odkazy

      -

      URLs (starting with: www, http, https, ftp, ftps, sftp and sftps) and email addresses are automatically turned into clickable links:

      +

      URL (začínající: www, http, https, ftp, ftps, sftp a sftps) a e-mailové adresy jsou automaticky převedeny na klikací odkazy:

       http://www.redmine.org, someone@foo.bar
      @@ -216,7 +225,6 @@
       
               

      Toto je odstavec zarovnaný na střed.

      -

      Citace

      Začněte odstavec s bq.

      @@ -285,9 +293,9 @@

      Zvýrazňování kódu

      -

      Výchozí zvýrazňování kódu zavisí na CodeRay, což je rychlá zvýrazňovací knihovna napsaná v Ruby. It currently supports c, clojure, cpp (c++, cplusplus), css, delphi (pascal), diff (patch), erb (eruby, rhtml), go, groovy, haml, html (xhtml), java, javascript (ecmascript, ecma_script, java_script, js), json, lua, php, python, ruby (irb), sass, sql, taskpaper, text (plain, plaintext), xml and yaml (yml) languages, where the names inside parentheses are aliases.

      +

      Výchozí zvýrazňování kódu zavisí na CodeRay, což je rychlá zvýrazňovací knihovna napsaná v Ruby. Aktuálně podporuje: c, clojure, cpp (c++, cplusplus), css, delphi (pascal), diff (patch), erb (eruby, rhtml), go, groovy, haml, html (xhtml), java, javascript (ecmascript, ecma_script, java_script, js), json, lua, php, python, ruby (irb), sass, sql, taskpaper, text (plain, plaintext), xml a yaml (yml) jazyky, jejichž jména jsou v závorkách jsou aliasy.

      -

      You can highlight code at any place that supports wiki formatting using this syntax (note that the language name or alias is case-insensitive):

      +

      Kód můžete na stránce zvýraznit pomocí následující syntaxe (záleží na velikosti písma jazyku nebo aliasu):

       <pre><code class="ruby">
      diff -Nru redmine-3.4.2/public/help/cs/wiki_syntax_markdown.html redmine-3.4.4/public/help/cs/wiki_syntax_markdown.html
      --- redmine-3.4.2/public/help/cs/wiki_syntax_markdown.html	2017-07-16 18:19:12.000000000 +0000
      +++ redmine-3.4.4/public/help/cs/wiki_syntax_markdown.html	2018-01-08 19:37:10.000000000 +0000
      @@ -2,7 +2,7 @@
       
       
       
      -Wiki formatting
      +Wiki formátování
       
       
       
      @@ -27,18 +27,18 @@
       Ordered list1. Položka 1
         1. Pod
      2. Položka 2
      1. Položka 1
        1. Pod
      2. Položka 2
      Nadpisy -Heading 1# Nadpis 1

      Title 1

      -Heading 2## Nadpis 2

      Title 2

      -Heading 3### Nadpis 3

      Title 3

      +Heading 1# Nadpis 1

      Nadpis 1

      +Heading 2## Nadpis 2

      Nadpis 2

      +Heading 3### Nadpis 3

      Nadpis 3

      Odkazy http://foo.barhttp://foo.bar [Odkaz](http://foo.bar)Foo Redmine odkazy -Link to a Wiki page[[Wiki page]]Wiki page -Úkol #12Issue #12 -Revize r43Revision r43 +Link to a Wiki page[[Wiki stránka]]Wiki stránka +Úkol #12Úkol #12 +Revize r43Revize r43 commit:f30e13e43f30e13e4 source:some/filesource:some/file diff -Nru redmine-3.4.2/public/help/cs/wiki_syntax_textile.html redmine-3.4.4/public/help/cs/wiki_syntax_textile.html --- redmine-3.4.2/public/help/cs/wiki_syntax_textile.html 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/help/cs/wiki_syntax_textile.html 2018-01-08 19:37:10.000000000 +0000 @@ -2,7 +2,7 @@ -Wiki formatting +Wiki formátování Binary files /tmp/tmpJhrJv5/FHTAdPV41c/redmine-3.4.2/public/images/anonymous.png and /tmp/tmpJhrJv5/gJ1xTENH9Y/redmine-3.4.4/public/images/anonymous.png differ diff -Nru redmine-3.4.2/public/javascripts/application.js redmine-3.4.4/public/javascripts/application.js --- redmine-3.4.2/public/javascripts/application.js 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/javascripts/application.js 2018-01-08 19:37:10.000000000 +0000 @@ -120,7 +120,7 @@ function addFilter(field, operator, values) { var fieldId = field.replace('.', '_'); var tr = $('#tr_'+fieldId); - + var filterOptions = availableFilters[field]; if (!filterOptions) return; @@ -587,6 +587,8 @@ $(document).ready(function(){ $(".drdn .autocomplete").val(''); + // This variable is used to focus selected project + var selected; $(".drdn-trigger").click(function(e){ var drdn = $(this).closest(".drdn"); if (drdn.hasClass("expanded")) { @@ -594,6 +596,8 @@ } else { $(".drdn").removeClass("expanded"); drdn.addClass("expanded"); + selected = $('.drdn-items a.selected'); // Store selected project + selected.focus(); // Calling focus to scroll to selected project if (!isMobile()) { drdn.find(".autocomplete").focus(); } @@ -603,14 +607,22 @@ $(document).click(function(e){ if ($(e.target).closest(".drdn").length < 1) { $(".drdn.expanded").removeClass("expanded"); - } + } }); observeSearchfield('projects-quick-search', null, $('#projects-quick-search').data('automcomplete-url')); $(".drdn-content").keydown(function(event){ var items = $(this).find(".drdn-items"); - var focused = items.find("a:focus"); + + // If a project is selected set focused to selected only once + if (selected && selected.length > 0) { + var focused = selected; + selected = undefined; + } + else { + var focused = items.find("a:focus"); + } switch (event.which) { case 40: //down if (focused.length > 0) { diff -Nru redmine-3.4.2/public/javascripts/attachments.js redmine-3.4.4/public/javascripts/attachments.js --- redmine-3.4.2/public/javascripts/attachments.js 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/javascripts/attachments.js 2018-01-08 19:37:10.000000000 +0000 @@ -214,7 +214,8 @@ var cursorPosition = $textarea.prop('selectionStart'); var description = $textarea.val(); var sanitizedFilename = file.name.replace(/[\/\?\%\*\:\|\"\'<>\n\r]+/, '_'); - var inlineFilename = encodeURIComponent(sanitizedFilename); + var inlineFilename = encodeURIComponent(sanitizedFilename) + .replace(/[!()]/g, function(match) { return "%" + match.charCodeAt(0).toString(16) }); var newLineBefore = true; var newLineAfter = true; if(cursorPosition === 0 || description.substr(cursorPosition-1,1).match(/\r|\n/)) { diff -Nru redmine-3.4.2/public/javascripts/jstoolbar/lang/jstoolbar-es.js redmine-3.4.4/public/javascripts/jstoolbar/lang/jstoolbar-es.js --- redmine-3.4.2/public/javascripts/jstoolbar/lang/jstoolbar-es.js 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/javascripts/jstoolbar/lang/jstoolbar-es.js 2018-01-08 19:37:10.000000000 +0000 @@ -7,7 +7,7 @@ jsToolBar.strings['Heading 1'] = 'Encabezado 1'; jsToolBar.strings['Heading 2'] = 'Encabezado 2'; jsToolBar.strings['Heading 3'] = 'Encabezado 3'; -jsToolBar.strings['Highlighted code'] = 'Highlighted code'; +jsToolBar.strings['Highlighted code'] = 'Código resaltado'; jsToolBar.strings['Unordered list'] = 'Lista sin ordenar'; jsToolBar.strings['Ordered list'] = 'Lista ordenada'; jsToolBar.strings['Quote'] = 'Citar'; diff -Nru redmine-3.4.2/public/javascripts/jstoolbar/lang/jstoolbar-es-pa.js redmine-3.4.4/public/javascripts/jstoolbar/lang/jstoolbar-es-pa.js --- redmine-3.4.2/public/javascripts/jstoolbar/lang/jstoolbar-es-pa.js 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/javascripts/jstoolbar/lang/jstoolbar-es-pa.js 2018-01-08 19:37:10.000000000 +0000 @@ -7,7 +7,7 @@ jsToolBar.strings['Heading 1'] = 'Encabezado 1'; jsToolBar.strings['Heading 2'] = 'Encabezado 2'; jsToolBar.strings['Heading 3'] = 'Encabezado 3'; -jsToolBar.strings['Highlighted code'] = 'Highlighted code'; +jsToolBar.strings['Highlighted code'] = 'Código resaltado'; jsToolBar.strings['Unordered list'] = 'Lista sin ordenar'; jsToolBar.strings['Ordered list'] = 'Lista ordenada'; jsToolBar.strings['Quote'] = 'Citar'; diff -Nru redmine-3.4.2/public/stylesheets/application.css redmine-3.4.4/public/stylesheets/application.css --- redmine-3.4.2/public/stylesheets/application.css 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/public/stylesheets/application.css 2018-01-08 19:37:10.000000000 +0000 @@ -274,6 +274,7 @@ tr.issue.idnt-9 td.subject {padding-left: 152px; background-position: 136px 50%;} table.issue-report {table-layout:fixed;} +table.issue-report th {white-space: normal;} tr.entry { border: 1px solid #f8f8f8; } tr.entry td { white-space: nowrap; } @@ -479,7 +480,7 @@ fieldset#filters td.operator { width:130px; } fieldset#filters td.operator select {max-width:120px;} fieldset#filters td.values { white-space:nowrap; } -fieldset#filters td.values select {min-width:130px; max-width:200px;} +fieldset#filters td.values select {min-width:130px;} fieldset#filters td.values input {height:1em;} #filters-table {width:60%; float:left;} @@ -902,9 +903,9 @@ table.cal td.odd p.day-num {color: #bbb;} table.cal td.today {background:#ffffdd;} table.cal td.today p.day-num {font-weight: bold;} -table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} -table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} -table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting a.issue, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .ending a.issue, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting.ending a.issue, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} p.cal.legend span {display:block;} /***** Tooltips ******/ @@ -1150,6 +1151,10 @@ .gantt_subjects { font-size: 0.8em; } .gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } +.gantt_subjects .issue-subject img.icon-gravatar { + margin: 2px 5px 0px 2px; +} + .task { position: absolute; height:8px; diff -Nru redmine-3.4.2/test/fixtures/mail_handler/ticket_with_empty_attachment.eml redmine-3.4.4/test/fixtures/mail_handler/ticket_with_empty_attachment.eml --- redmine-3.4.2/test/fixtures/mail_handler/ticket_with_empty_attachment.eml 1970-01-01 00:00:00.000000000 +0000 +++ redmine-3.4.4/test/fixtures/mail_handler/ticket_with_empty_attachment.eml 2018-01-08 19:37:10.000000000 +0000 @@ -0,0 +1,58 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sat, 21 Jun 2008 15:53:25 +0200 +Message-ID: <002301c8d3a6$2cdf6950$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: Ticket created by email with attachment +Date: Sat, 21 Jun 2008 15:53:25 +0200 +MIME-Version: 1.0 +Content-Type: multipart/mixed; + boundary="----=_NextPart_000_001F_01C8D3B6.F05C5270" +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +This is a multi-part message in MIME format. + +------=_NextPart_000_001F_01C8D3B6.F05C5270 +Content-Type: multipart/alternative; + boundary="----=_NextPart_001_0020_01C8D3B6.F05C5270" + + +------=_NextPart_001_0020_01C8D3B6.F05C5270 +Content-Type: text/plain; + charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + +This is a new ticket with attachments +------=_NextPart_001_0020_01C8D3B6.F05C5270 +Content-Type: text/html; + charset="iso-8859-1" +Content-Transfer-Encoding: quoted-printable + + + + + + + + +
      This is  a new ticket with=20 +attachments
      + +------=_NextPart_001_0020_01C8D3B6.F05C5270-- + +------=_NextPart_000_001F_01C8D3B6.F05C5270 +Content-Type: application/json; + name="response.json" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="response.json" + + +------=_NextPart_000_001F_01C8D3B6.F05C5270-- + diff -Nru redmine-3.4.2/test/functional/account_controller_test.rb redmine-3.4.4/test/functional/account_controller_test.rb --- redmine-3.4.2/test/functional/account_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/account_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -220,6 +220,15 @@ assert_response 302 end + def test_login_should_strip_whitespaces_from_user_name + post :login, :params => { + :username => ' jsmith ', + :password => 'jsmith' + } + assert_response 302 + assert_equal 2, @request.session[:user_id] + end + def test_get_logout_should_not_logout @request.session[:user_id] = 2 get :logout @@ -385,6 +394,21 @@ end end + def test_lost_password_with_whitespace_should_send_email_to_the_address + Token.delete_all + + assert_difference 'ActionMailer::Base.deliveries.size' do + assert_difference 'Token.count' do + post :lost_password, params: { + mail: ' JSmith@somenet.foo ' + } + assert_redirected_to '/login' + end + end + mail = ActionMailer::Base.deliveries.last + assert_equal ['jsmith@somenet.foo'], mail.bcc + end + def test_lost_password_using_additional_email_address_should_send_email_to_the_address EmailAddress.create!(:user_id => 2, :address => 'anotherAddress@foo.bar') Token.delete_all diff -Nru redmine-3.4.2/test/functional/attachments_visibility_test.rb redmine-3.4.4/test/functional/attachments_visibility_test.rb --- redmine-3.4.2/test/functional/attachments_visibility_test.rb 1970-01-01 00:00:00.000000000 +0000 +++ redmine-3.4.4/test/functional/attachments_visibility_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -0,0 +1,58 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2017 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../test_helper', __FILE__) + +class AttachmentsVisibilityTest < Redmine::ControllerTest + tests AttachmentsController + fixtures :users, :email_addresses, :projects, :roles, :members, :member_roles, + :enabled_modules, :projects_trackers, :issue_statuses, :enumerations, + :issues, :trackers, :versions + + def setup + set_tmp_attachments_directory + + @field = IssueCustomField.generate!(:field_format => 'attachment', :visible => true) + @attachment = new_record(Attachment) do + issue = Issue.generate + issue.custom_field_values = {@field.id => {:file => mock_file}} + issue.save! + end + end + + def test_attachment_should_be_visible + @request.session[:user_id] = 2 # manager + get :show, :params => {:id => @attachment.id} + assert_response :success + + @field.update!(:visible => false, :role_ids => [1]) + get :show, :params => {:id => @attachment.id} + assert_response :success + end + + def test_attachment_should_be_visible_with_permission + @request.session[:user_id] = 3 # developer + get :show, :params => {:id => @attachment.id} + assert_response :success + + @field.update!(:visible => false, :role_ids => [1]) + get :show, :params => {:id => @attachment.id} + assert_response 403 + end +end diff -Nru redmine-3.4.2/test/functional/calendars_controller_test.rb redmine-3.4.4/test/functional/calendars_controller_test.rb --- redmine-3.4.2/test/functional/calendars_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/calendars_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -29,7 +29,8 @@ :issue_statuses, :issue_relations, :issue_categories, - :enumerations + :enumerations, + :queries def test_show get :show, :params => { @@ -94,4 +95,22 @@ assert_select 'td.even', :text => '10' end end + + def test_show_custom_query_with_multiple_sort_criteria + get :show, :params => { + :query_id => 5 + } + + assert_response :success + assert_select 'h2', :text => 'Open issues by priority and tracker' + end + + def test_show_custom_query_with_group_by_option + get :show, :params => { + :query_id => 6 + } + + assert_response :success + assert_select 'h2', :text => 'Open issues grouped by tracker' + end end diff -Nru redmine-3.4.2/test/functional/enumerations_controller_test.rb redmine-3.4.4/test/functional/enumerations_controller_test.rb --- redmine-3.4.2/test/functional/enumerations_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/enumerations_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -124,6 +124,18 @@ assert_select_error /name cannot be blank/i end + def test_update_position + assert_equal 2, Enumeration.find(2).position + put :update, :params => { + :id => 2, + :enumeration => { + :position => 1, + } + } + assert_response 302 + assert_equal 1, Enumeration.find(2).position + end + def test_destroy_enumeration_not_in_use assert_difference 'IssuePriority.count', -1 do delete :destroy, :params => { diff -Nru redmine-3.4.2/test/functional/issue_relations_controller_test.rb redmine-3.4.4/test/functional/issue_relations_controller_test.rb --- redmine-3.4.2/test/functional/issue_relations_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/issue_relations_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -82,8 +82,8 @@ assert_equal 'text/javascript', response.content_type end relation = IssueRelation.order('id DESC').first - assert_equal 3, relation.issue_from_id - assert_equal 1, relation.issue_to_id + assert_equal 1, relation.issue_from_id + assert_equal 3, relation.issue_to_id assert_include 'Bug #1', response.body end diff -Nru redmine-3.4.2/test/functional/issues_controller_test.rb redmine-3.4.4/test/functional/issues_controller_test.rb --- redmine-3.4.2/test/functional/issues_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/issues_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -941,6 +941,22 @@ assert_equal hours.sort.reverse, hours end + def test_index_sort_by_spent_hours_should_sort_by_visible_spent_hours + TimeEntry.delete_all + TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3) + TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4) + + get :index, :params => {:sort => "spent_hours:desc", :c => ['subject','spent_hours']} + assert_response :success + assert_equal [4.0, 3.0, 0.0], issues_in_list.map(&:spent_hours)[0..2] + + Project.find(3).disable_module!(:time_tracking) + + get :index, :params => {:sort => "spent_hours:desc", :c => ['subject','spent_hours']} + assert_response :success + assert_equal [3.0, 0.0, 0.0], issues_in_list.map(&:spent_hours)[0..2] + end + def test_index_sort_by_total_spent_hours get :index, :params => { :sort => 'total_spent_hours:desc' @@ -1379,6 +1395,22 @@ assert_select ".total-for-cf-#{field.id} span.value", :text => '9' end + def test_index_with_spent_time_total_should_sum_visible_spent_time_only + TimeEntry.delete_all + TimeEntry.generate!(:issue => Issue.generate!(:project_id => 1), :hours => 3) + TimeEntry.generate!(:issue => Issue.generate!(:project_id => 3), :hours => 4) + + get :index, :params => {:t => ["spent_hours"]} + assert_response :success + assert_select ".total-for-spent-hours span.value", :text => '7.00' + + Project.find(3).disable_module!(:time_tracking) + + get :index, :params => {:t => ["spent_hours"]} + assert_response :success + assert_select ".total-for-spent-hours span.value", :text => '3.00' + end + def test_index_totals_should_default_to_settings with_settings :issue_list_default_totals => ['estimated_hours'] do get :index @@ -3828,6 +3860,7 @@ assert_select 'input[type=checkbox][name=?][checked=checked]', 'issue[watcher_user_ids][]', 1 assert_select 'input[type=checkbox][name=?][checked=checked][value=?]', 'issue[watcher_user_ids][]', user.id.to_s + assert_select 'input[type=hidden][name=?][value=?]', 'issue[watcher_user_ids][]', '', 1 end def test_new_as_copy_with_invalid_issue_should_respond_with_404 @@ -4164,6 +4197,46 @@ assert_equal 1, issue.project_id end + def test_create_as_copy_with_watcher_user_ids_should_copy_watchers + @request.session[:user_id] = 2 + copied = Issue.generate! + copied.add_watcher User.find(2) + copied.add_watcher User.find(3) + + assert_difference 'Issue.count' do + post :create, :params => { + :project_id => 1, + :copy_from => copied.id, + :issue => { + :subject => 'Copy cleared watchers', + :watcher_user_ids => ['', '3'] + } + } + end + issue = Issue.order('id DESC').first + assert_equal [3], issue.watcher_user_ids + end + + def test_create_as_copy_without_watcher_user_ids_should_not_copy_watchers + @request.session[:user_id] = 2 + copied = Issue.generate! + copied.add_watcher User.find(2) + copied.add_watcher User.find(3) + + assert_difference 'Issue.count' do + post :create, :params => { + :project_id => 1, + :copy_from => copied.id, + :issue => { + :subject => 'Copy cleared watchers', + :watcher_user_ids => [''] + } + } + end + issue = Issue.order('id DESC').first + assert_equal [], issue.watcher_user_ids + end + def test_get_edit @request.session[:user_id] = 2 get :edit, :params => { diff -Nru redmine-3.4.2/test/functional/queries_controller_test.rb redmine-3.4.4/test/functional/queries_controller_test.rb --- redmine-3.4.2/test/functional/queries_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/queries_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -556,6 +556,20 @@ assert_include ["eCookbook - 2.0", "3", "open"], json end + def test_version_filter_time_entries_with_project_id_should_return_filter_values + @request.session[:user_id] = 2 + get :filter, :params => { + :project_id => 1, + :type => 'TimeEntryQuery', + :name => 'issue.fixed_version_id' + } + + assert_response :success + assert_equal 'application/json', response.content_type + json = ActiveSupport::JSON.decode(response.body) + assert_include ["eCookbook - 2.0", "3", "open"], json + end + def test_filter_without_project_id_should_return_filter_values @request.session[:user_id] = 2 get :filter, :params => { @@ -567,4 +581,19 @@ json = ActiveSupport::JSON.decode(response.body) assert_include ["OnlineStore - Systemwide visible version", "7", "open"], json end + + def test_subproject_filter_time_entries_with_project_id_should_return_filter_values + @request.session[:user_id] = 2 + get :filter, :params => { + :project_id => 1, + :type => 'TimeEntryQuery', + :name => 'subproject_id' + } + + assert_response :success + assert_equal 'application/json', response.content_type + json = ActiveSupport::JSON.decode(response.body) + assert_equal 4, json.count + assert_include ["Private child of eCookbook","5"], json + end end diff -Nru redmine-3.4.2/test/functional/timelog_controller_test.rb redmine-3.4.4/test/functional/timelog_controller_test.rb --- redmine-3.4.2/test/functional/timelog_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/timelog_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -725,6 +725,8 @@ end def test_index_at_project_level + @request.session[:user_id] = 2 + get :index, :params => {:project_id => 'ecookbook', :c => ['project']} assert_response :success @@ -736,6 +738,9 @@ assert_select '.total-for-hours', :text => 'Hours: 162.90' assert_select 'form#query_form[action=?]', '/projects/ecookbook/time_entries' + + # 'Log time' shoudl link to log time on the filtered issue + assert_select 'a[href=?]', "/projects/ecookbook/time_entries/new" end def test_index_with_display_subprojects_issues_to_false_should_not_include_subproject_entries @@ -770,6 +775,9 @@ get :index, :params => {:project_id => 'ecookbook', :issue_id => issue.id.to_s, :set_filter => 1} assert_select '.total-for-hours', :text => 'Hours: 7.00' + + # 'Log time' shoudl link to log time on the filtered issue + assert_select 'a[href=?]', "/issues/#{issue.id}/time_entries/new" end def test_index_at_project_level_with_issue_fixed_version_id_short_filter @@ -783,6 +791,27 @@ assert_select '.total-for-hours', :text => 'Hours: 5.00' end + def test_index_at_project_level_with_multiple_issue_fixed_version_ids + version = Version.generate!(:project_id => 1) + version2 = Version.generate!(:project_id => 1) + issue = Issue.generate!(:project_id => 1, :fixed_version => version) + issue2 = Issue.generate!(:project_id => 1, :fixed_version => version2) + TimeEntry.generate!(:issue => issue, :hours => 2) + TimeEntry.generate!(:issue => issue2, :hours => 3) + @request.session[:user_id] = 2 + + get :index, :params => { + :project_id => 'ecookbook', + :f => ['issue.fixed_version_id'], + :op => {'issue.fixed_version_id' => '='}, + :v => {'issue.fixed_version_id' => [version.id.to_s,version2.id.to_s]} + } + assert_response :success + + assert_select 'tr.time-entry', 2 + assert_select '.total-for-hours', :text => 'Hours: 5.00' + end + def test_index_at_project_level_with_date_range get :index, :params => { :project_id => 'ecookbook', diff -Nru redmine-3.4.2/test/functional/wiki_controller_test.rb redmine-3.4.4/test/functional/wiki_controller_test.rb --- redmine-3.4.2/test/functional/wiki_controller_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/functional/wiki_controller_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -1,3 +1,5 @@ +# encoding: utf-8 +# # Redmine - project management software # Copyright (C) 2006-2017 Jean-Philippe Lang # @@ -1061,6 +1063,26 @@ assert_include 'h1. CookBook documentation v2', @response.body end + def test_show_filename_should_be_uri_encoded_for_ms_browsers + @request.session[:user_id] = 2 + title = 'Этика_менеджмента' + %w|pdf html txt|.each do |format| + # Non-MS browsers + @request.user_agent = "" + get :show, :project_id => 1, :id => title, :format => format + assert_response :success + assert_equal "attachment; filename=\"#{title}.#{format}\"", + @response.headers['Content-Disposition'] + # Microsoft's browsers: filename should be URI encoded + @request.user_agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36 Edge/15.15063' + get :show, :project_id => 1, :id => title, :format => format + assert_response :success + filename = URI.encode("#{title}.#{format}") + assert_equal "attachment; filename=\"#{filename}\"", + @response.headers['Content-Disposition'] + end + end + def test_edit_unprotected_page # Non members can edit unprotected wiki pages @request.session[:user_id] = 4 diff -Nru redmine-3.4.2/test/unit/helpers/application_helper_test.rb redmine-3.4.4/test/unit/helpers/application_helper_test.rb --- redmine-3.4.2/test/unit/helpers/application_helper_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/helpers/application_helper_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -1328,6 +1328,7 @@ end def test_avatar_enabled + tag_for_anonymous_re = %r{src="/images/anonymous.png(\?\d+)?"} with_settings :gravatar_enabled => '1' do assert avatar(User.find_by_mail('jsmith@somenet.foo')).include?(Digest::MD5.hexdigest('jsmith@somenet.foo')) assert avatar('jsmith ').include?(Digest::MD5.hexdigest('jsmith@somenet.foo')) @@ -1339,8 +1340,10 @@ # The default class of the img tag should be gravatar assert avatar('jsmith ').include?('class="gravatar"') assert !avatar('jsmith ', :class => 'picture').include?('class="gravatar"') - assert_nil avatar('jsmith') - assert_nil avatar(nil) + assert_match tag_for_anonymous_re, avatar('jsmith') + assert_match tag_for_anonymous_re, avatar(nil) + # Avatar for anonymous user + assert_match tag_for_anonymous_re, avatar(User.anonymous) end end diff -Nru redmine-3.4.2/test/unit/issue_nested_set_concurrency_test.rb redmine-3.4.4/test/unit/issue_nested_set_concurrency_test.rb --- redmine-3.4.2/test/unit/issue_nested_set_concurrency_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/issue_nested_set_concurrency_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -27,7 +27,7 @@ self.use_transactional_fixtures = false def setup - skip if sqlite? + skip if sqlite? || mysql? CustomField.delete_all end diff -Nru redmine-3.4.2/test/unit/issue_relation_test.rb redmine-3.4.4/test/unit/issue_relation_test.rb --- redmine-3.4.2/test/unit/issue_relation_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/issue_relation_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -65,6 +65,20 @@ assert_equal from, relation.issue_to end + def test_cannot_create_inverse_relates_relations + from = Issue.find(1) + to = Issue.find(2) + + relation1 = IssueRelation.new :issue_from => from, :issue_to => to, + :relation_type => IssueRelation::TYPE_RELATES + assert relation1.save + + relation2 = IssueRelation.new :issue_from => to, :issue_to => from, + :relation_type => IssueRelation::TYPE_RELATES + assert !relation2.save + assert_not_equal [], relation2.errors[:base] + end + def test_follows_relation_should_not_be_reversed_if_validation_fails from = Issue.find(1) to = Issue.find(2) diff -Nru redmine-3.4.2/test/unit/issue_test.rb redmine-3.4.4/test/unit/issue_test.rb --- redmine-3.4.2/test/unit/issue_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/issue_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -26,6 +26,7 @@ :issue_statuses, :issue_categories, :issue_relations, :workflows, :enumerations, :issues, :journals, :journal_details, + :watchers, :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, :time_entries @@ -127,7 +128,7 @@ def test_estimated_hours_should_be_validated set_language_if_valid 'en' - ['-2'].each do |invalid| + ['-2', '123abc'].each do |invalid| issue = Issue.new(:estimated_hours => invalid) assert !issue.valid? assert_include 'Estimated time is invalid', issue.errors.full_messages @@ -1882,8 +1883,6 @@ issue = Issue.find(2) issue.assigned_to = nil assert_include user.mail, issue.recipients - issue.save! - assert !issue.recipients.include?(user.mail) end def test_recipients_should_not_include_users_that_cannot_view_the_issue @@ -2278,11 +2277,13 @@ end def test_overdue - assert Issue.new(:due_date => 1.day.ago.to_date).overdue? - assert !Issue.new(:due_date => Date.today).overdue? - assert !Issue.new(:due_date => 1.day.from_now.to_date).overdue? + User.current = nil + today = User.current.today + assert Issue.new(:due_date => (today - 1.day).to_date).overdue? + assert !Issue.new(:due_date => today).overdue? + assert !Issue.new(:due_date => (today + 1.day).to_date).overdue? assert !Issue.new(:due_date => nil).overdue? - assert !Issue.new(:due_date => 1.day.ago.to_date, + assert !Issue.new(:due_date => (today - 1.day).to_date, :status => IssueStatus.where(:is_closed => true).first ).overdue? end @@ -2440,9 +2441,8 @@ def test_update_should_notify_previous_assignee ActionMailer::Base.deliveries.clear - user = User.find(3) - user.members.update_all ["mail_notification = ?", false] - user.update! :mail_notification => 'only_assigned' + user = User.generate!(:mail_notification => 'only_assigned') + Issue.where(:id => 2).update_all(:assigned_to_id => user.id) with_settings :notified_events => %w(issue_updated) do issue = Issue.find(2) diff -Nru redmine-3.4.2/test/unit/lib/redmine/field_format/attachment_format_visibility_test.rb redmine-3.4.4/test/unit/lib/redmine/field_format/attachment_format_visibility_test.rb --- redmine-3.4.2/test/unit/lib/redmine/field_format/attachment_format_visibility_test.rb 1970-01-01 00:00:00.000000000 +0000 +++ redmine-3.4.4/test/unit/lib/redmine/field_format/attachment_format_visibility_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -0,0 +1,59 @@ +# Redmine - project management software +# Copyright (C) 2006-2017 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../../test_helper', __FILE__) +require 'redmine/field_format' + +class AttachmentFormatVisibilityTest < ActionView::TestCase + fixtures :projects, :enabled_modules, :projects_trackers, + :roles, :members, :member_roles, + :users, :email_addresses, + :trackers, :issue_statuses, :enumerations, :issue_categories, + :versions, :issues + + def setup + set_tmp_attachments_directory + end + + def test_attachment_should_be_visible_with_visible_custom_field + field = IssueCustomField.generate!(:field_format => 'attachment', :visible => true) + attachment = new_record(Attachment) do + issue = Issue.generate + issue.custom_field_values = {field.id => {:file => mock_file}} + issue.save! + end + + assert attachment.visible?(manager = User.find(2)) + assert attachment.visible?(developer = User.find(3)) + assert attachment.visible?(non_member = User.find(7)) + assert attachment.visible?(User.anonymous) + end + + def test_attachment_should_be_visible_with_limited_visibility_custom_field + field = IssueCustomField.generate!(:field_format => 'attachment', :visible => false, :role_ids => [1]) + attachment = new_record(Attachment) do + issue = Issue.generate + issue.custom_field_values = {field.id => {:file => mock_file}} + issue.save! + end + + assert attachment.visible?(manager = User.find(2)) + assert !attachment.visible?(developer = User.find(3)) + assert !attachment.visible?(non_member = User.find(7)) + assert !attachment.visible?(User.anonymous) + end +end diff -Nru redmine-3.4.2/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb redmine-3.4.4/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb --- redmine-3.4.2/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -21,6 +21,8 @@ HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION + HgCommandAborted = Redmine::Scm::Adapters::MercurialAdapter::HgCommandAborted + HgCommandArgumentError = Redmine::Scm::Adapters::MercurialAdapter::HgCommandArgumentError REPOSITORY_PATH = repository_path('mercurial') CHAR_1_HEX = "\xc3\x9c" @@ -443,6 +445,23 @@ assert_equal "UTF-8", adpt2.path_encoding end + def test_bad_early_options + assert_nil @adapter.diff('sources/welcome_controller.rb', + '--config=alias.rhdiff=!xterm') + assert_raise HgCommandArgumentError do + @adapter.entries('--debugger') + end + assert_raise HgCommandAborted do + @adapter.revisions(nil, nil, nil, limit: '--repo=otherrepo') + end + assert_raise HgCommandAborted do + @adapter.nodes_in_branch('default', limit: '--repository=otherrepo') + end + assert_raise HgCommandAborted do + @adapter.nodes_in_branch('-Rotherrepo') + end + end + private def test_hgversion_for(hgversion, version) diff -Nru redmine-3.4.2/test/unit/mail_handler_test.rb redmine-3.4.4/test/unit/mail_handler_test.rb --- redmine-3.4.2/test/unit/mail_handler_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/mail_handler_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -627,6 +627,14 @@ assert_equal content, File.read(attachment.diskfile).force_encoding('CP852') end + def test_empty_attachment_should_not_be_imported + issue = submit_email( + 'ticket_with_empty_attachment.eml', + issue: { project: 'ecookbook' } + ) + assert_equal 0, issue.attachments.size + end + def test_multiple_inline_text_parts_should_be_appended_to_issue_description issue = submit_email('multiple_text_parts.eml', :issue => {:project => 'ecookbook'}) assert_include 'first', issue.description diff -Nru redmine-3.4.2/test/unit/user_test.rb redmine-3.4.4/test/unit/user_test.rb --- redmine-3.4.2/test/unit/user_test.rb 2017-07-16 18:19:12.000000000 +0000 +++ redmine-3.4.4/test/unit/user_test.rb 2018-01-08 19:37:10.000000000 +0000 @@ -1196,10 +1196,6 @@ issue.assigned_to = new_assignee assert assignee.notify_about?(issue) assert new_assignee.notify_about?(issue) - - issue.save! - assert !assignee.notify_about?(issue) - assert new_assignee.notify_about?(issue) end def test_notify_about_news