Compare commits
82
Commits
master
...
2.1-stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cdd427a0e | ||
|
|
de2b7c2879 | ||
|
|
f0aad8c2a8 | ||
|
|
68b923640e | ||
|
|
4e2fbf440b | ||
|
|
5572b6c715 | ||
|
|
d63f0fa5b0 | ||
|
|
dff772b066 | ||
|
|
fb2cbdc6cc | ||
|
|
6062a0a89d | ||
|
|
0ebf95d819 | ||
|
|
14879e24c4 | ||
|
|
ca0b289479 | ||
|
|
e36a611f81 | ||
|
|
6c2eec59d8 | ||
|
|
905ed3aa75 | ||
|
|
bb4c530ba2 | ||
|
|
e3958ef577 | ||
|
|
c5f2dadb2c | ||
|
|
af8dcccb7b | ||
|
|
c0742ed9e6 | ||
|
|
8c7ae20402 | ||
|
|
06b68f1948 | ||
|
|
b51203bc83 | ||
|
|
f578a5c4f6 | ||
|
|
17d1907747 | ||
|
|
0e241bb857 | ||
|
|
9dcde53dab | ||
|
|
a44521527a | ||
|
|
f12590fa5c | ||
|
|
a1c6f710aa | ||
|
|
3ad82e4665 | ||
|
|
eef3b5b5ca | ||
|
|
ab69845ea2 | ||
|
|
af51a68b34 | ||
|
|
d5c08680f6 | ||
|
|
9b82b948e3 | ||
|
|
1c8510bc80 | ||
|
|
23861c7cc1 | ||
|
|
6550343cb9 | ||
|
|
a70cf2f833 | ||
|
|
0f219b973a | ||
|
|
d02e5e54a8 | ||
|
|
c050028102 | ||
|
|
012ffdf9e8 | ||
|
|
9e3aeeef88 | ||
|
|
21b162a624 | ||
|
|
b7e999d1aa | ||
|
|
284d03e1f8 | ||
|
|
3b4126e14f | ||
|
|
46a76ecb6e | ||
|
|
5a74edef89 | ||
|
|
2f9c2e6bd3 | ||
|
|
2df7c0ff3a | ||
|
|
f5d5077d2b | ||
|
|
94a1eb21a4 | ||
|
|
1f80a4b0d9 | ||
|
|
55220950d2 | ||
|
|
daea57a37c | ||
|
|
fe61739108 | ||
|
|
a4cd96e8b0 | ||
|
|
804302ce61 | ||
|
|
89ecbe9cdc | ||
|
|
aac3e1e51c | ||
|
|
595fef0d68 | ||
|
|
65a6e3985e | ||
|
|
f27a0eca5b | ||
|
|
2d34ab9235 | ||
|
|
03bff3308f | ||
|
|
006a1b4fd7 | ||
|
|
9095874a07 | ||
|
|
8ecfd1dcf8 | ||
|
|
35584bc53a | ||
|
|
21a16e0958 | ||
|
|
76d24e44bf | ||
|
|
efbdef9357 | ||
|
|
5eab4af70d | ||
|
|
96b2e00015 | ||
|
|
9939fbeef6 | ||
|
|
b369f82d15 | ||
|
|
0ad5dfaba0 | ||
|
|
d7d18689b7 |
@@ -19,6 +19,7 @@
|
|||||||
/public/plugin_assets
|
/public/plugin_assets
|
||||||
/tmp/*
|
/tmp/*
|
||||||
/tmp/cache/*
|
/tmp/cache/*
|
||||||
|
/tmp/pdf/*
|
||||||
/tmp/sessions/*
|
/tmp/sessions/*
|
||||||
/tmp/sockets/*
|
/tmp/sockets/*
|
||||||
/tmp/test/*
|
/tmp/test/*
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ public/dispatch.*
|
|||||||
public/plugin_assets
|
public/plugin_assets
|
||||||
tmp/*
|
tmp/*
|
||||||
tmp/cache/*
|
tmp/cache/*
|
||||||
|
tmp/pdf/*
|
||||||
tmp/sessions/*
|
tmp/sessions/*
|
||||||
tmp/sockets/*
|
tmp/sockets/*
|
||||||
tmp/test/*
|
tmp/test/*
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
source 'http://rubygems.org'
|
source 'http://rubygems.org'
|
||||||
|
|
||||||
gem 'rails', '3.2.8'
|
gem 'rails', '3.2.11'
|
||||||
gem "jquery-rails", "~> 2.0.2"
|
gem "jquery-rails", "~> 2.0.2"
|
||||||
gem "i18n", "~> 0.6.0"
|
gem "i18n", "~> 0.6.0"
|
||||||
gem "coderay", "~> 1.0.6"
|
gem "coderay", "~> 1.0.6"
|
||||||
@@ -41,7 +41,7 @@ end
|
|||||||
|
|
||||||
platforms :mri_18, :mingw_18 do
|
platforms :mri_18, :mingw_18 do
|
||||||
group :mysql do
|
group :mysql do
|
||||||
gem "mysql"
|
gem "mysql", "~> 2.8.1"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ class AccountController < ApplicationController
|
|||||||
def onthefly_creation_failed(user, auth_source_options = { })
|
def onthefly_creation_failed(user, auth_source_options = { })
|
||||||
@user = user
|
@user = user
|
||||||
session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
|
session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
|
||||||
render register_path
|
render :action => 'register'
|
||||||
end
|
end
|
||||||
|
|
||||||
def invalid_credentials
|
def invalid_credentials
|
||||||
|
|||||||
@@ -398,7 +398,7 @@ private
|
|||||||
end
|
end
|
||||||
|
|
||||||
@issue.project = @project
|
@issue.project = @project
|
||||||
@issue.author = User.current
|
@issue.author ||= User.current
|
||||||
# Tracker must be set before custom field values
|
# Tracker must be set before custom field values
|
||||||
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
||||||
if @issue.tracker.nil?
|
if @issue.tracker.nil?
|
||||||
|
|||||||
@@ -26,7 +26,8 @@ class PreviewsController < ApplicationController
|
|||||||
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
|
if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n")
|
||||||
@description = nil
|
@description = nil
|
||||||
end
|
end
|
||||||
@notes = params[:notes]
|
# params[:notes] is useful for preview of notes in issue history
|
||||||
|
@notes = params[:notes] || (params[:issue] ? params[:issue][:notes] : nil)
|
||||||
else
|
else
|
||||||
@description = (params[:issue] ? params[:issue][:description] : nil)
|
@description = (params[:issue] ? params[:issue][:description] : nil)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -129,15 +129,6 @@ class WikiController < ApplicationController
|
|||||||
# don't keep previous comment
|
# don't keep previous comment
|
||||||
@content.comments = nil
|
@content.comments = nil
|
||||||
|
|
||||||
if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text]
|
|
||||||
attachments = Attachment.attach_files(@page, params[:attachments])
|
|
||||||
render_attachment_warning_if_needed(@page)
|
|
||||||
# don't save content if text wasn't changed
|
|
||||||
@page.save
|
|
||||||
redirect_to :action => 'show', :project_id => @project, :id => @page.title
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
@content.comments = params[:content][:comments]
|
@content.comments = params[:content][:comments]
|
||||||
@text = params[:content][:text]
|
@text = params[:content][:text]
|
||||||
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
|
if params[:section].present? && Redmine::WikiFormatting.supports_section_edit?
|
||||||
@@ -149,8 +140,8 @@ class WikiController < ApplicationController
|
|||||||
@content.text = @text
|
@content.text = @text
|
||||||
end
|
end
|
||||||
@content.author = User.current
|
@content.author = User.current
|
||||||
@page.content = @content
|
|
||||||
if @page.save
|
if @page.save_with_content
|
||||||
attachments = Attachment.attach_files(@page, params[:attachments])
|
attachments = Attachment.attach_files(@page, params[:attachments])
|
||||||
render_attachment_warning_if_needed(@page)
|
render_attachment_warning_if_needed(@page)
|
||||||
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
|
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
|
||||||
@@ -239,7 +230,7 @@ class WikiController < ApplicationController
|
|||||||
|
|
||||||
# Export wiki to a single pdf or html file
|
# Export wiki to a single pdf or html file
|
||||||
def export
|
def export
|
||||||
@pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments], :limit => 75)
|
@pages = @wiki.pages.all(:order => 'title', :include => [:content, :attachments])
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html {
|
||||||
export = render_to_string :action => 'export_multiple', :layout => false
|
export = render_to_string :action => 'export_multiple', :layout => false
|
||||||
|
|||||||
@@ -795,11 +795,10 @@ module ApplicationHelper
|
|||||||
if repository && User.current.allowed_to?(:browse_repository, project)
|
if repository && User.current.allowed_to?(:browse_repository, project)
|
||||||
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$}
|
||||||
path, rev, anchor = $1, $3, $5
|
path, rev, anchor = $1, $3, $5
|
||||||
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :repository_id => repository.identifier_param,
|
link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param,
|
||||||
:path => to_path_param(path),
|
:path => to_path_param(path),
|
||||||
:rev => rev,
|
:rev => rev,
|
||||||
:anchor => anchor,
|
:anchor => anchor},
|
||||||
:format => (prefix == 'export' ? 'raw' : nil)},
|
|
||||||
:class => (prefix == 'export' ? 'source download' : 'source')
|
:class => (prefix == 'export' ? 'source download' : 'source')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1029,6 +1028,11 @@ module ApplicationHelper
|
|||||||
content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options))
|
content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Helper to render JSON in views
|
||||||
|
def raw_json(arg)
|
||||||
|
arg.to_json.to_s.gsub('/', '\/').html_safe
|
||||||
|
end
|
||||||
|
|
||||||
def back_url
|
def back_url
|
||||||
url = params[:back_url]
|
url = params[:back_url]
|
||||||
if url.nil? && referer = request.env['HTTP_REFERER']
|
if url.nil? && referer = request.env['HTTP_REFERER']
|
||||||
@@ -1095,8 +1099,14 @@ module ApplicationHelper
|
|||||||
unless @calendar_headers_tags_included
|
unless @calendar_headers_tags_included
|
||||||
@calendar_headers_tags_included = true
|
@calendar_headers_tags_included = true
|
||||||
content_for :header_tags do
|
content_for :header_tags do
|
||||||
|
start_of_week = Setting.start_of_week
|
||||||
|
start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank?
|
||||||
|
# Redmine uses 1..7 (monday..sunday) in settings and locales
|
||||||
|
# JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
|
||||||
|
start_of_week = start_of_week.to_i % 7
|
||||||
|
|
||||||
tags = javascript_tag(
|
tags = javascript_tag(
|
||||||
"var datepickerOptions={dateFormat: 'yy-mm-dd', " +
|
"var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
|
||||||
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
|
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
|
||||||
path_to_image('/images/calendar.png') +
|
path_to_image('/images/calendar.png') +
|
||||||
"', showButtonPanel: true};")
|
"', showButtonPanel: true};")
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ module ContextMenusHelper
|
|||||||
end
|
end
|
||||||
if options.delete(:disabled)
|
if options.delete(:disabled)
|
||||||
options.delete(:method)
|
options.delete(:method)
|
||||||
options.delete(:confirm)
|
options.delete(:data)
|
||||||
options.delete(:onclick)
|
options[:onclick] = 'return false;'
|
||||||
options[:class] << ' disabled'
|
options[:class] << ' disabled'
|
||||||
url = '#'
|
url = '#'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -130,7 +130,13 @@ class CustomField < ActiveRecord::Base
|
|||||||
possible_values_options = possible_values_options(customized)
|
possible_values_options = possible_values_options(customized)
|
||||||
if possible_values_options.present?
|
if possible_values_options.present?
|
||||||
keyword = keyword.to_s.downcase
|
keyword = keyword.to_s.downcase
|
||||||
possible_values_options.detect {|text, id| text.downcase == keyword}.try(:last)
|
if v = possible_values_options.detect {|text, id| text.downcase == keyword}
|
||||||
|
if v.is_a?(Array)
|
||||||
|
v.last
|
||||||
|
else
|
||||||
|
v
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
keyword
|
keyword
|
||||||
end
|
end
|
||||||
|
|||||||
+26
-18
@@ -84,17 +84,21 @@ class Issue < ActiveRecord::Base
|
|||||||
# Returns a SQL conditions string used to find all issues visible by the specified user
|
# Returns a SQL conditions string used to find all issues visible by the specified user
|
||||||
def self.visible_condition(user, options={})
|
def self.visible_condition(user, options={})
|
||||||
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
|
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
|
||||||
case role.issues_visibility
|
if user.logged?
|
||||||
when 'all'
|
case role.issues_visibility
|
||||||
nil
|
when 'all'
|
||||||
when 'default'
|
nil
|
||||||
user_ids = [user.id] + user.groups.map(&:id)
|
when 'default'
|
||||||
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
user_ids = [user.id] + user.groups.map(&:id)
|
||||||
when 'own'
|
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||||
user_ids = [user.id] + user.groups.map(&:id)
|
when 'own'
|
||||||
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
user_ids = [user.id] + user.groups.map(&:id)
|
||||||
|
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||||
|
else
|
||||||
|
'1=0'
|
||||||
|
end
|
||||||
else
|
else
|
||||||
'1=0'
|
"(#{table_name}.is_private = #{connection.quoted_false})"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -102,15 +106,19 @@ class Issue < ActiveRecord::Base
|
|||||||
# Returns true if usr or current user is allowed to view the issue
|
# Returns true if usr or current user is allowed to view the issue
|
||||||
def visible?(usr=nil)
|
def visible?(usr=nil)
|
||||||
(usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
|
(usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
|
||||||
case role.issues_visibility
|
if user.logged?
|
||||||
when 'all'
|
case role.issues_visibility
|
||||||
true
|
when 'all'
|
||||||
when 'default'
|
true
|
||||||
!self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to)
|
when 'default'
|
||||||
when 'own'
|
!self.is_private? || (self.author == user || user.is_or_belongs_to?(assigned_to))
|
||||||
self.author == user || user.is_or_belongs_to?(assigned_to)
|
when 'own'
|
||||||
|
self.author == user || user.is_or_belongs_to?(assigned_to)
|
||||||
|
else
|
||||||
|
false
|
||||||
|
end
|
||||||
else
|
else
|
||||||
false
|
!self.is_private?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ class MailHandler < ActionMailer::Base
|
|||||||
|
|
||||||
def dispatch
|
def dispatch
|
||||||
headers = [email.in_reply_to, email.references].flatten.compact
|
headers = [email.in_reply_to, email.references].flatten.compact
|
||||||
|
subject = email.subject.to_s
|
||||||
if headers.detect {|h| h.to_s =~ MESSAGE_ID_RE}
|
if headers.detect {|h| h.to_s =~ MESSAGE_ID_RE}
|
||||||
klass, object_id = $1, $2.to_i
|
klass, object_id = $1, $2.to_i
|
||||||
method_name = "receive_#{klass}_reply"
|
method_name = "receive_#{klass}_reply"
|
||||||
@@ -132,9 +133,9 @@ class MailHandler < ActionMailer::Base
|
|||||||
else
|
else
|
||||||
# ignoring it
|
# ignoring it
|
||||||
end
|
end
|
||||||
elsif m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
|
elsif m = subject.match(ISSUE_REPLY_SUBJECT_RE)
|
||||||
receive_issue_reply(m[1].to_i)
|
receive_issue_reply(m[1].to_i)
|
||||||
elsif m = email.subject.match(MESSAGE_REPLY_SUBJECT_RE)
|
elsif m = subject.match(MESSAGE_REPLY_SUBJECT_RE)
|
||||||
receive_message_reply(m[1].to_i)
|
receive_message_reply(m[1].to_i)
|
||||||
else
|
else
|
||||||
dispatch_to_default
|
dispatch_to_default
|
||||||
@@ -244,9 +245,26 @@ class MailHandler < ActionMailer::Base
|
|||||||
def add_attachments(obj)
|
def add_attachments(obj)
|
||||||
if email.attachments && email.attachments.any?
|
if email.attachments && email.attachments.any?
|
||||||
email.attachments.each do |attachment|
|
email.attachments.each do |attachment|
|
||||||
|
filename = attachment.filename
|
||||||
|
unless filename.respond_to?(:encoding)
|
||||||
|
# try to reencode to utf8 manually with ruby1.8
|
||||||
|
h = attachment.header['Content-Disposition']
|
||||||
|
unless h.nil?
|
||||||
|
begin
|
||||||
|
if m = h.value.match(/filename\*[0-9\*]*=([^=']+)'/)
|
||||||
|
filename = Redmine::CodesetUtil.to_utf8(filename, m[1])
|
||||||
|
elsif m = h.value.match(/filename=.*=\?([^\?]+)\?[BbQq]\?/)
|
||||||
|
# http://tools.ietf.org/html/rfc2047#section-4
|
||||||
|
filename = Redmine::CodesetUtil.to_utf8(filename, m[1])
|
||||||
|
end
|
||||||
|
rescue
|
||||||
|
# nop
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
obj.attachments << Attachment.create(:container => obj,
|
obj.attachments << Attachment.create(:container => obj,
|
||||||
:file => attachment.decoded,
|
:file => attachment.decoded,
|
||||||
:filename => attachment.filename,
|
:filename => filename,
|
||||||
:author => user,
|
:author => user,
|
||||||
:content_type => attachment.mime_type)
|
:content_type => attachment.mime_type)
|
||||||
end
|
end
|
||||||
@@ -373,7 +391,8 @@ class MailHandler < ActionMailer::Base
|
|||||||
# try to reencode to utf8 manually with ruby1.8
|
# try to reencode to utf8 manually with ruby1.8
|
||||||
begin
|
begin
|
||||||
if h = email.header[:subject]
|
if h = email.header[:subject]
|
||||||
if m = h.value.match(/^=\?([^\?]+)\?/)
|
# http://tools.ietf.org/html/rfc2047#section-4
|
||||||
|
if m = h.value.match(/=\?([^\?]+)\?[BbQq]\?/)
|
||||||
subject = Redmine::CodesetUtil.to_utf8(subject, m[1])
|
subject = Redmine::CodesetUtil.to_utf8(subject, m[1])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -30,13 +30,13 @@ class Principal < ActiveRecord::Base
|
|||||||
if q.blank?
|
if q.blank?
|
||||||
{}
|
{}
|
||||||
else
|
else
|
||||||
q = q.to_s.downcase
|
q = q.to_s
|
||||||
pattern = "%#{q}%"
|
pattern = "%#{q}%"
|
||||||
sql = "LOWER(login) LIKE :p OR LOWER(firstname) LIKE :p OR LOWER(lastname) LIKE :p OR LOWER(mail) LIKE :p"
|
sql = "LOWER(login) LIKE LOWER(:p) OR LOWER(firstname) LIKE LOWER(:p) OR LOWER(lastname) LIKE LOWER(:p) OR LOWER(mail) LIKE LOWER(:p)"
|
||||||
params = {:p => pattern}
|
params = {:p => pattern}
|
||||||
if q =~ /^(.+)\s+(.+)$/
|
if q =~ /^(.+)\s+(.+)$/
|
||||||
a, b = "#{$1}%", "#{$2}%"
|
a, b = "#{$1}%", "#{$2}%"
|
||||||
sql << " OR (LOWER(firstname) LIKE :a AND LOWER(lastname) LIKE :b) OR (LOWER(firstname) LIKE :b AND LOWER(lastname) LIKE :a)"
|
sql << " OR (LOWER(firstname) LIKE LOWER(:a) AND LOWER(lastname) LIKE LOWER(:b)) OR (LOWER(firstname) LIKE LOWER(:b) AND LOWER(lastname) LIKE LOWER(:a))"
|
||||||
params.merge!(:a => a, :b => b)
|
params.merge!(:a => a, :b => b)
|
||||||
end
|
end
|
||||||
{:conditions => [sql, params]}
|
{:conditions => [sql, params]}
|
||||||
|
|||||||
@@ -427,5 +427,9 @@ class Repository < ActiveRecord::Base
|
|||||||
connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||||
connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||||
connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
|
connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
|
||||||
|
clear_extra_info_of_changesets
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_extra_info_of_changesets
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -255,4 +255,15 @@ class Repository::Git < Repository
|
|||||||
:order => 'committed_on DESC'
|
:order => 'committed_on DESC'
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clear_extra_info_of_changesets
|
||||||
|
return if extra_info.nil?
|
||||||
|
v = extra_info["extra_report_last_commit"]
|
||||||
|
write_attribute(:extra_info, nil)
|
||||||
|
h = {}
|
||||||
|
h["extra_report_last_commit"] = v
|
||||||
|
merge_extra_info(h)
|
||||||
|
self.save
|
||||||
|
end
|
||||||
|
private :clear_extra_info_of_changesets
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -133,6 +133,11 @@ class Role < ActiveRecord::Base
|
|||||||
self.builtin != 0
|
self.builtin != 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Return true if the role is the anonymous role
|
||||||
|
def anonymous?
|
||||||
|
builtin == 2
|
||||||
|
end
|
||||||
|
|
||||||
# Return true if the role is a project member role
|
# Return true if the role is a project member role
|
||||||
def member?
|
def member?
|
||||||
!self.builtin?
|
!self.builtin?
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class UserPreference < ActiveRecord::Base
|
|||||||
if attribute_present? attr_name
|
if attribute_present? attr_name
|
||||||
super
|
super
|
||||||
else
|
else
|
||||||
h = read_attribute(:others).dup || {}
|
h = (read_attribute(:others) || {}).dup
|
||||||
h.update(attr_name => value)
|
h.update(attr_name => value)
|
||||||
write_attribute(:others, h)
|
write_attribute(:others, h)
|
||||||
value
|
value
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class Version < ActiveRecord::Base
|
|||||||
validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true
|
validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :not_a_date, :allow_nil => true
|
||||||
validates_inclusion_of :status, :in => VERSION_STATUSES
|
validates_inclusion_of :status, :in => VERSION_STATUSES
|
||||||
validates_inclusion_of :sharing, :in => VERSION_SHARINGS
|
validates_inclusion_of :sharing, :in => VERSION_SHARINGS
|
||||||
|
validate :validate_version
|
||||||
|
|
||||||
scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}}
|
scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}}
|
||||||
scope :open, :conditions => {:status => 'open'}
|
scope :open, :conditions => {:status => 'open'}
|
||||||
@@ -275,4 +276,10 @@ class Version < ActiveRecord::Base
|
|||||||
progress
|
progress
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def validate_version
|
||||||
|
if effective_date.nil? && @attributes['effective_date'].present?
|
||||||
|
errors.add :effective_date, :not_a_date
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -172,6 +172,21 @@ class WikiPage < ActiveRecord::Base
|
|||||||
self.parent = parent_page
|
self.parent = parent_page
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Saves the page and its content if text was changed
|
||||||
|
def save_with_content
|
||||||
|
ret = nil
|
||||||
|
transaction do
|
||||||
|
if new_record?
|
||||||
|
# Rails automatically saves associated content
|
||||||
|
ret = save
|
||||||
|
else
|
||||||
|
ret = save && (content.text_changed? ? content.save : true)
|
||||||
|
end
|
||||||
|
raise ActiveRecord::Rollback unless ret
|
||||||
|
end
|
||||||
|
ret
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def validate_parent_title
|
def validate_parent_title
|
||||||
|
|||||||
@@ -3,6 +3,6 @@
|
|||||||
<% if @message.present? %>
|
<% if @message.present? %>
|
||||||
<p id="errorExplanation"><%=h @message %></p>
|
<p id="errorExplanation"><%=h @message %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<p><a href="javascript:history.back()">Back</a></p>
|
<p><a href="javascript:history.back()"><%= l(:button_back) %></a></p>
|
||||||
|
|
||||||
<% html_title @status %>
|
<% html_title @status %>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
|
<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
|
||||||
</span>
|
</span>
|
||||||
<%= submit_tag l(:button_add) %>
|
<%= submit_tag l(:button_add) %>
|
||||||
<%= toggle_link l(:button_cancel), 'new-relation-form'%>
|
<%= link_to_function l(:button_cancel), '$("#new-relation-form").hide();'%>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<%= javascript_tag "observeAutocompleteField('relation_issue_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %>
|
<%= javascript_tag "observeAutocompleteField('relation_issue_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
<tr class="group open">
|
<tr class="group open">
|
||||||
<td colspan="<%= query.columns.size + 2 %>">
|
<td colspan="<%= query.columns.size + 2 %>">
|
||||||
<span class="expander" onclick="toggleRowGroup(this);"> </span>
|
<span class="expander" onclick="toggleRowGroup(this);"> </span>
|
||||||
<%= group.blank? ? 'None' : column_content(@query.group_by_column, issue) %> <span class="count">(<%= @issue_count_by_group[group] %>)</span>
|
<%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, issue) %> <span class="count">(<%= @issue_count_by_group[group] %>)</span>
|
||||||
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
|
<%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", "toggleAllRowGroups(this)", :class => 'toggle-all') %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -1,2 +1,8 @@
|
|||||||
$("#journal-<%= @journal.id %>-notes").hide();
|
$("#journal-<%= @journal.id %>-notes").hide();
|
||||||
$("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>');
|
|
||||||
|
if ($("form#journal-<%= @journal.id %>-form").length > 0) {
|
||||||
|
// journal edit form already loaded
|
||||||
|
$("#journal-<%= @journal.id %>-form").show();
|
||||||
|
} else {
|
||||||
|
$("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>');
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
<tr class="<%= cycle 'odd', 'even' %>">
|
<tr class="<%= cycle 'odd', 'even' %>">
|
||||||
<td>
|
<td>
|
||||||
<%= link_to repository.identifier,
|
<%= link_to repository.identifier,
|
||||||
{:controller => 'repositories', :action => 'show',:id => @project, :repository_id => repository.identifier_param} if repository.identifier_param.present? %>
|
{:controller => 'repositories', :action => 'show',:id => @project, :repository_id => repository.identifier_param} if repository.identifier.present? %>
|
||||||
</td>
|
</td>
|
||||||
<td align="center"><%= checked_image repository.is_default? %></td>
|
<td align="center"><%= checked_image repository.is_default? %></td>
|
||||||
<td><%=h repository.scm_name %></td>
|
<td><%=h repository.scm_name %></td>
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<%= javascript_tag do %>
|
<%= javascript_tag do %>
|
||||||
var operatorLabels = <%= raw Query.operators_labels.to_json %>;
|
var operatorLabels = <%= raw_json Query.operators_labels %>;
|
||||||
var operatorByType = <%= raw Query.operators_by_filter_type.to_json %>;
|
var operatorByType = <%= raw_json Query.operators_by_filter_type %>;
|
||||||
var availableFilters = <%= raw query.available_filters_as_json.to_json %>;
|
var availableFilters = <%= raw_json query.available_filters_as_json %>;
|
||||||
var labelDayPlural = "<%= raw escape_javascript(l(:label_day_plural)) %>";
|
var labelDayPlural = <%= raw_json l(:label_day_plural) %>;
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
initFilters();
|
initFilters();
|
||||||
<% query.filters.each do |field, options| %>
|
<% query.filters.each do |field, options| %>
|
||||||
addFilter("<%= field %>", <%= raw query.operator_for(field).to_json %>, <%= raw query.values_for(field).to_json %>);
|
addFilter("<%= field %>", <%= raw_json query.operator_for(field) %>, <%= raw_json query.values_for(field) %>);
|
||||||
<% end %>
|
<% end %>
|
||||||
});
|
});
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
<%= javascript_include_tag 'raphael.js' %>
|
<%= javascript_tag do %>
|
||||||
<%= javascript_include_tag 'revision_graph.js' %>
|
|
||||||
<script type="text/javascript" charset="utf-8">
|
|
||||||
function revisionGraphHandler(){
|
function revisionGraphHandler(){
|
||||||
drawRevisionGraph(
|
drawRevisionGraph(
|
||||||
document.getElementById('holder'),
|
document.getElementById('holder'),
|
||||||
@@ -10,5 +8,11 @@ function revisionGraphHandler(){
|
|||||||
}
|
}
|
||||||
$(document).ready(revisionGraphHandler);
|
$(document).ready(revisionGraphHandler);
|
||||||
$(window).resize(revisionGraphHandler);
|
$(window).resize(revisionGraphHandler);
|
||||||
</script>
|
<% end %>
|
||||||
|
|
||||||
<div id="holder" class="revision-graph"></div>
|
<div id="holder" class="revision-graph"></div>
|
||||||
|
|
||||||
|
<% content_for :header_tags do %>
|
||||||
|
<%= javascript_include_tag 'raphael' %>
|
||||||
|
<%= javascript_include_tag 'revision_graph' %>
|
||||||
|
<% end %>
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
<h2><%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %></h2>
|
<h2><%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %></h2>
|
||||||
|
|
||||||
<!-- Choose view type -->
|
<!-- Choose view type -->
|
||||||
<%= form_tag({:path => to_path_param(@path)}, :method => 'get') do %>
|
<%= form_tag({:action => 'diff', :id => @project,
|
||||||
<%= hidden_field_tag('rev', params[:rev]) if params[:rev] %>
|
:repository_id => @repository.identifier_param,
|
||||||
|
:path => to_path_param(@path), :rev=> @rev}, :method => 'get') do %>
|
||||||
<%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>
|
<%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>
|
||||||
<p>
|
<p>
|
||||||
<label><%= l(:label_view_diff) %></label>
|
<label><%= l(:label_view_diff) %></label>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= form_tag(
|
<%= form_tag(
|
||||||
{:controller => 'repositories', :action => 'revision', :id => @project,
|
{:controller => 'repositories', :action => 'revision', :id => @project,
|
||||||
:repository_id => @repository.identifier_param}
|
:repository_id => @repository.identifier_param},
|
||||||
|
:method => :get
|
||||||
) do %>
|
) do %>
|
||||||
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %>
|
<%= l(:label_revision) %>: <%= text_field_tag 'rev', @rev, :size => 8 %>
|
||||||
<%= submit_tag 'OK' %>
|
<%= submit_tag 'OK' %>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<%= error_messages_for 'role' %>
|
<%= error_messages_for 'role' %>
|
||||||
|
|
||||||
|
<% unless @role.anonymous? %>
|
||||||
<div class="box tabular">
|
<div class="box tabular">
|
||||||
<% unless @role.builtin? %>
|
<% unless @role.builtin? %>
|
||||||
<p><%= f.text_field :name, :required => true %></p>
|
<p><%= f.text_field :name, :required => true %></p>
|
||||||
@@ -11,6 +12,7 @@
|
|||||||
<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name, params[:copy_workflow_from] || @copy_from.try(:id))) %></p>
|
<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name, params[:copy_workflow_from] || @copy_from.try(:id))) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
</div>
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
<h3><%= l(:label_permissions) %></h3>
|
<h3><%= l(:label_permissions) %></h3>
|
||||||
<div class="box tabular" id="permissions">
|
<div class="box tabular" id="permissions">
|
||||||
|
|||||||
@@ -80,9 +80,8 @@ bs:
|
|||||||
format:
|
format:
|
||||||
unit: 'KM'
|
unit: 'KM'
|
||||||
format: '%u %n'
|
format: '%u %n'
|
||||||
separator:
|
negative_format: '%u -%n'
|
||||||
delimiter:
|
delimiter: ''
|
||||||
precision:
|
|
||||||
percentage:
|
percentage:
|
||||||
format:
|
format:
|
||||||
delimiter: ""
|
delimiter: ""
|
||||||
|
|||||||
+12
-14
@@ -84,9 +84,7 @@ de:
|
|||||||
format:
|
format:
|
||||||
unit: '€'
|
unit: '€'
|
||||||
format: '%n %u'
|
format: '%n %u'
|
||||||
separator:
|
delimiter: ''
|
||||||
delimiter:
|
|
||||||
precision:
|
|
||||||
percentage:
|
percentage:
|
||||||
format:
|
format:
|
||||||
delimiter: ""
|
delimiter: ""
|
||||||
@@ -846,7 +844,7 @@ de:
|
|||||||
button_show: Anzeigen
|
button_show: Anzeigen
|
||||||
|
|
||||||
status_active: aktiv
|
status_active: aktiv
|
||||||
status_registered: angemeldet
|
status_registered: nicht aktivierte
|
||||||
status_locked: gesperrt
|
status_locked: gesperrt
|
||||||
|
|
||||||
version_status_open: offen
|
version_status_open: offen
|
||||||
@@ -1019,8 +1017,8 @@ de:
|
|||||||
description_date_from: Startdatum eintragen
|
description_date_from: Startdatum eintragen
|
||||||
description_date_to: Enddatum eintragen
|
description_date_to: Enddatum eintragen
|
||||||
|
|
||||||
label_parent_revision: Parent
|
label_parent_revision: Vorgänger
|
||||||
label_child_revision: Child
|
label_child_revision: Nachfolger
|
||||||
error_scm_annotate_big_text_file: Der Eintrag kann nicht umgesetzt werden, da er die maximale Textlänge überschreitet.
|
error_scm_annotate_big_text_file: Der Eintrag kann nicht umgesetzt werden, da er die maximale Textlänge überschreitet.
|
||||||
setting_default_issue_start_date_to_creation_date: Aktuelles Datum als Beginn für neue Tickets verwenden
|
setting_default_issue_start_date_to_creation_date: Aktuelles Datum als Beginn für neue Tickets verwenden
|
||||||
button_edit_section: Diesen Bereich bearbeiten
|
button_edit_section: Diesen Bereich bearbeiten
|
||||||
@@ -1070,14 +1068,14 @@ de:
|
|||||||
field_timeout: Auszeit (in Sekunden)
|
field_timeout: Auszeit (in Sekunden)
|
||||||
setting_thumbnails_enabled: Vorschaubilder von Dateianhängen anzeigen
|
setting_thumbnails_enabled: Vorschaubilder von Dateianhängen anzeigen
|
||||||
setting_thumbnails_size: Größe der Vorschaubilder (in Pixel)
|
setting_thumbnails_size: Größe der Vorschaubilder (in Pixel)
|
||||||
label_status_transitions: Status transitions
|
label_status_transitions: Statusänderungen
|
||||||
label_fields_permissions: Fields permissions
|
label_fields_permissions: Feldberechtigungen
|
||||||
label_readonly: Nur-Lese-Zugriff
|
label_readonly: Nur-Lese-Zugriff
|
||||||
label_required: Erforderlich
|
label_required: Erforderlich
|
||||||
text_repository_identifier_info: 'Kleinbuchstaben (a-z), Ziffern, Binde- und Unterstriche erlaubt.<br />Einmal gespeichert, kann die Kennung nicht mehr geändert werden.'
|
text_repository_identifier_info: 'Kleinbuchstaben (a-z), Ziffern, Binde- und Unterstriche erlaubt.<br />Einmal gespeichert, kann die Kennung nicht mehr geändert werden.'
|
||||||
field_board_parent: Parent forum
|
field_board_parent: Übergeordnetes Forum
|
||||||
label_attribute_of_project: Project's %{name}
|
label_attribute_of_project: "%{name} des Projekts"
|
||||||
label_attribute_of_author: Author's %{name}
|
label_attribute_of_author: "%{name} des Autors"
|
||||||
label_attribute_of_assigned_to: Assignee's %{name}
|
label_attribute_of_assigned_to: "%{name} des Bearbeiters"
|
||||||
label_attribute_of_fixed_version: Target version's %{name}
|
label_attribute_of_fixed_version: "%{name} der Zielversion"
|
||||||
label_copy_subtasks: Copy subtasks
|
label_copy_subtasks: Unteraufgaben kopieren
|
||||||
|
|||||||
@@ -1087,9 +1087,9 @@ ja:
|
|||||||
label_readonly: 読み取り専用
|
label_readonly: 読み取り専用
|
||||||
label_required: 必須
|
label_required: 必須
|
||||||
text_repository_identifier_info: アルファベット小文字(a-z)・数字・ハイフン・アンダースコアが使えます。<br />識別子は後で変更することはできません。
|
text_repository_identifier_info: アルファベット小文字(a-z)・数字・ハイフン・アンダースコアが使えます。<br />識別子は後で変更することはできません。
|
||||||
field_board_parent: Parent forum
|
field_board_parent: 親フォーラム
|
||||||
label_attribute_of_project: Project's %{name}
|
label_attribute_of_project: プロジェクトの %{name}
|
||||||
label_attribute_of_author: Author's %{name}
|
label_attribute_of_author: 作成者の %{name}
|
||||||
label_attribute_of_assigned_to: Assignee's %{name}
|
label_attribute_of_assigned_to: 担当者の %{name}
|
||||||
label_attribute_of_fixed_version: Target version's %{name}
|
label_attribute_of_fixed_version: 対象バージョンの %{name}
|
||||||
label_copy_subtasks: Copy subtasks
|
label_copy_subtasks: 子チケットをコピー
|
||||||
|
|||||||
+50
-50
@@ -49,7 +49,7 @@ nl:
|
|||||||
one: "ongeveer 1 uur"
|
one: "ongeveer 1 uur"
|
||||||
other: "ongeveer %{count} uren"
|
other: "ongeveer %{count} uren"
|
||||||
x_hours:
|
x_hours:
|
||||||
one: "1 hour"
|
one: "1 uur"
|
||||||
other: "%{count} hours"
|
other: "%{count} hours"
|
||||||
x_days:
|
x_days:
|
||||||
one: "1 dag"
|
one: "1 dag"
|
||||||
@@ -990,58 +990,58 @@ nl:
|
|||||||
description_all_columns: Alle kolommen
|
description_all_columns: Alle kolommen
|
||||||
button_export: Exporteren
|
button_export: Exporteren
|
||||||
label_export_options: "%{export_format} export opties"
|
label_export_options: "%{export_format} export opties"
|
||||||
error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})
|
error_attachment_too_big: Dit bestand kan niet worden geupload omdat het de maximaal toegestane grootte overschrijd (%{max_size})
|
||||||
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
notice_failed_to_save_time_entries: "Opslaan gefaald voor %{count} tijdsnotatie(s) van %{total} geselecteerde: %{ids}."
|
||||||
label_x_issues:
|
label_x_issues:
|
||||||
zero: 0 issue
|
zero: 0 incidenten
|
||||||
one: 1 issue
|
one: 1 incidenten
|
||||||
other: "%{count} issues"
|
other: "%{count} incidenten"
|
||||||
label_repository_new: New repository
|
label_repository_new: Nieuw repository
|
||||||
field_repository_is_default: Main repository
|
field_repository_is_default: Hoofd repository
|
||||||
label_copy_attachments: Copy attachments
|
label_copy_attachments: Copieer bijlage(n)
|
||||||
label_item_position: "%{position}/%{count}"
|
label_item_position: "%{position}/%{count}"
|
||||||
label_completed_versions: Completed versions
|
label_completed_versions: Versies compleet
|
||||||
field_multiple: Multiple values
|
field_multiple: Meerdere waardes
|
||||||
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
|
setting_commit_cross_project_ref: Sta toe om incidenten van alle projecten te refereren en oplossen
|
||||||
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes
|
text_issue_conflict_resolution_add_notes: Voeg mijn notities toe en annuleer andere wijzigingen
|
||||||
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
|
text_issue_conflict_resolution_overwrite: Voeg mijn wijzigingen alsnog toe (voorgaande notities worden bewaard, maar sommige kunnen overschreden worden)
|
||||||
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
|
notice_issue_update_conflict: Dit incident is reeds geupdate door een andere gebruiker terwijl jij bezig was
|
||||||
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
|
text_issue_conflict_resolution_cancel: Annuleer mijn wijzigingen en geef pagina opnieuw weer %{link}
|
||||||
permission_manage_related_issues: Manage related issues
|
permission_manage_related_issues: Beheer gerelateerde incidenten
|
||||||
field_auth_source_ldap_filter: LDAP filter
|
field_auth_source_ldap_filter: LDAP filter
|
||||||
label_search_for_watchers: Search for watchers to add
|
label_search_for_watchers: Zoek om monitoorders toe te voegen
|
||||||
notice_account_deleted: Your account has been permanently deleted.
|
notice_account_deleted: Uw account is permanent verwijderd
|
||||||
setting_unsubscribe: Allow users to delete their own account
|
setting_unsubscribe: Sta gebruikers toe hun eigen account te verwijderen
|
||||||
button_delete_my_account: Delete my account
|
button_delete_my_account: Verwijder mijn account
|
||||||
text_account_destroy_confirmation: |-
|
text_account_destroy_confirmation: |-
|
||||||
Are you sure you want to proceed?
|
Weet u zeker dat u door wilt gaan?
|
||||||
Your account will be permanently deleted, with no way to reactivate it.
|
Uw account wordt permanent verwijderd zonder mogelijkheid deze te heractiveren.
|
||||||
error_session_expired: Your session has expired. Please login again.
|
error_session_expired: Uw sessie is verlopen. U dient opnieuw in te loggen.
|
||||||
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
|
text_session_expiration_settings: "Waarschuwing: door deze instelling te wijzigen kan sessies laten verlopen inclusief de uwe"
|
||||||
setting_session_lifetime: Session maximum lifetime
|
setting_session_lifetime: Maximale sessieduur
|
||||||
setting_session_timeout: Session inactivity timeout
|
setting_session_timeout: Sessie inactiviteit timeout
|
||||||
label_session_expiration: Session expiration
|
label_session_expiration: Sessie verlopen
|
||||||
permission_close_project: Close / reopen the project
|
permission_close_project: Sluit / heropen project
|
||||||
label_show_closed_projects: View closed projects
|
label_show_closed_projects: Gesloten projecten weergeven
|
||||||
button_close: Close
|
button_close: Sluiten
|
||||||
button_reopen: Reopen
|
button_reopen: Heropen
|
||||||
project_status_active: active
|
project_status_active: actief
|
||||||
project_status_closed: closed
|
project_status_closed: gesloten
|
||||||
project_status_archived: archived
|
project_status_archived: gearchiveerd
|
||||||
text_project_closed: This project is closed and read-only.
|
text_project_closed: Dit project is gesloten en op alleen-lezen
|
||||||
notice_user_successful_create: User %{id} created.
|
notice_user_successful_create: Gebruiker %{id} aangemaakt.
|
||||||
field_core_fields: Standard fields
|
field_core_fields: Standaard verleden
|
||||||
field_timeout: Timeout (in seconds)
|
field_timeout: Timeout (in seconds)
|
||||||
setting_thumbnails_enabled: Display attachment thumbnails
|
setting_thumbnails_enabled: Geef bijlage miniaturen weer
|
||||||
setting_thumbnails_size: Thumbnails size (in pixels)
|
setting_thumbnails_size: Grootte miniaturen (in pixels)
|
||||||
label_status_transitions: Status transitions
|
label_status_transitions: Status transitie
|
||||||
label_fields_permissions: Fields permissions
|
label_fields_permissions: Permissie velden
|
||||||
label_readonly: Read-only
|
label_readonly: Alleen-lezen
|
||||||
label_required: Required
|
label_required: Verplicht
|
||||||
text_repository_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.<br />Eenmaal opgeslagen kan de identifier niet worden gewijzigd.'
|
text_repository_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.<br />Eenmaal opgeslagen kan de identifier niet worden gewijzigd.'
|
||||||
field_board_parent: Parent forum
|
field_board_parent: Hoofd forum
|
||||||
label_attribute_of_project: Project's %{name}
|
label_attribute_of_project: Project %{name}
|
||||||
label_attribute_of_author: Author's %{name}
|
label_attribute_of_author: Auteur(s) %{name}
|
||||||
label_attribute_of_assigned_to: Assignee's %{name}
|
label_attribute_of_assigned_to: Toegewezen %{name}
|
||||||
label_attribute_of_fixed_version: Target version's %{name}
|
label_attribute_of_fixed_version: Target versions %{name}
|
||||||
label_copy_subtasks: Copy subtasks
|
label_copy_subtasks: Kopieer subtaken
|
||||||
|
|||||||
+35
-35
@@ -971,64 +971,64 @@
|
|||||||
setting_issue_group_assignment: Tillat tildeling av saker til grupper
|
setting_issue_group_assignment: Tillat tildeling av saker til grupper
|
||||||
label_diff: diff
|
label_diff: diff
|
||||||
|
|
||||||
description_query_sort_criteria_direction: Sort direction
|
description_query_sort_criteria_direction: Sorteringsretning
|
||||||
description_project_scope: Search scope
|
description_project_scope: Search scope
|
||||||
description_filter: Filter
|
description_filter: Filter
|
||||||
description_user_mail_notification: Mail notification settings
|
description_user_mail_notification: Mail notification settings
|
||||||
description_date_from: Enter start date
|
description_date_from: Oppgi startdato
|
||||||
description_message_content: Message content
|
description_message_content: Meldingsinnhold
|
||||||
description_available_columns: Available Columns
|
description_available_columns: Tilgjengelige kolonner
|
||||||
description_date_range_interval: Choose range by selecting start and end date
|
description_date_range_interval: Velg datointervall ved å spesifisere start- og sluttdato
|
||||||
description_issue_category_reassign: Choose issue category
|
description_issue_category_reassign: Choose issue category
|
||||||
description_search: Searchfield
|
description_search: Søkefelt
|
||||||
description_notes: Notes
|
description_notes: Notes
|
||||||
description_date_range_list: Choose range from list
|
description_date_range_list: Choose range from list
|
||||||
description_choose_project: Projects
|
description_choose_project: Prosjekter
|
||||||
description_date_to: Enter end date
|
description_date_to: Oppgi sluttdato
|
||||||
description_query_sort_criteria_attribute: Sort attribute
|
description_query_sort_criteria_attribute: Sort attribute
|
||||||
description_wiki_subpages_reassign: Choose new parent page
|
description_wiki_subpages_reassign: Velg ny overordnet side
|
||||||
description_selected_columns: Selected Columns
|
description_selected_columns: Valgte kolonner
|
||||||
label_parent_revision: Parent
|
label_parent_revision: Overordnet
|
||||||
label_child_revision: Child
|
label_child_revision: Underordnet
|
||||||
error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size.
|
error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size.
|
||||||
setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues
|
setting_default_issue_start_date_to_creation_date: Bruk dagens dato som startdato for nye saker
|
||||||
button_edit_section: Edit this section
|
button_edit_section: Rediger denne seksjonen
|
||||||
setting_repositories_encodings: Attachments and repositories encodings
|
setting_repositories_encodings: Attachments and repositories encodings
|
||||||
description_all_columns: All Columns
|
description_all_columns: Alle kolonnene
|
||||||
button_export: Export
|
button_export: Eksporter
|
||||||
label_export_options: "%{export_format} export options"
|
label_export_options: "%{export_format} eksportvalg"
|
||||||
error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})
|
error_attachment_too_big: Filen overstiger maksimum filstørrelse (%{max_size}) og kan derfor ikke lastes opp
|
||||||
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
||||||
label_x_issues:
|
label_x_issues:
|
||||||
zero: 0 sak
|
zero: 0 sak
|
||||||
one: 1 sak
|
one: 1 sak
|
||||||
other: "%{count} saker"
|
other: "%{count} saker"
|
||||||
label_repository_new: New repository
|
label_repository_new: Nytt depot
|
||||||
field_repository_is_default: Main repository
|
field_repository_is_default: Hoveddepot
|
||||||
label_copy_attachments: Copy attachments
|
label_copy_attachments: Kopier vedlegg
|
||||||
label_item_position: "%{position}/%{count}"
|
label_item_position: "%{position}/%{count}"
|
||||||
label_completed_versions: Completed versions
|
label_completed_versions: Completed versions
|
||||||
text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.<br />Once saved, the identifier cannot be changed.
|
text_project_identifier_info: Kun små bokstaver (a-z), tall, bindestrek (-) og "underscore" (_) er tillatt.<br />Etter lagring er det ikke mulig å gjøre endringer.
|
||||||
field_multiple: Multiple values
|
field_multiple: Flere verdier
|
||||||
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
|
setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed
|
||||||
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes
|
text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes
|
||||||
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
|
text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten)
|
||||||
notice_issue_update_conflict: The issue has been updated by an other user while you were editing it.
|
notice_issue_update_conflict: Saken ble oppdatert av en annen bruker mens du redigerte den.
|
||||||
text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link}
|
text_issue_conflict_resolution_cancel: Forkast alle endringen mine og vis %{link} på nytt
|
||||||
permission_manage_related_issues: Manage related issues
|
permission_manage_related_issues: Manage related issues
|
||||||
field_auth_source_ldap_filter: LDAP filter
|
field_auth_source_ldap_filter: LDAP filter
|
||||||
label_search_for_watchers: Search for watchers to add
|
label_search_for_watchers: Search for watchers to add
|
||||||
notice_account_deleted: Your account has been permanently deleted.
|
notice_account_deleted: Din konto er ugjenkallelig slettet.
|
||||||
setting_unsubscribe: Allow users to delete their own account
|
setting_unsubscribe: Tillat brukere å slette sin egen konto
|
||||||
button_delete_my_account: Delete my account
|
button_delete_my_account: Slett kontoen min
|
||||||
text_account_destroy_confirmation: |-
|
text_account_destroy_confirmation: |-
|
||||||
Are you sure you want to proceed?
|
Er du sikker på at du ønsker å fortsette?
|
||||||
Your account will be permanently deleted, with no way to reactivate it.
|
Kontoen din vil bli ugjenkallelig slettet uten mulighet for å reaktiveres igjen.
|
||||||
error_session_expired: Your session has expired. Please login again.
|
error_session_expired: Økten har gått ut på tid. Vennligst logg på igjen.
|
||||||
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
|
text_session_expiration_settings: "Advarsel: ved å endre disse innstillingene kan aktive økter gå ut på tid, inkludert din egen."
|
||||||
setting_session_lifetime: Session maximum lifetime
|
setting_session_lifetime: Øktenes makslengde
|
||||||
setting_session_timeout: Session inactivity timeout
|
setting_session_timeout: Økten er avsluttet på grunn av inaktivitet
|
||||||
label_session_expiration: Session expiration
|
label_session_expiration: Økten er avsluttet
|
||||||
permission_close_project: Close / reopen the project
|
permission_close_project: Close / reopen the project
|
||||||
label_show_closed_projects: View closed projects
|
label_show_closed_projects: View closed projects
|
||||||
button_close: Close
|
button_close: Close
|
||||||
|
|||||||
+28
-28
@@ -1121,7 +1121,7 @@ ru:
|
|||||||
button_export: Экспорт
|
button_export: Экспорт
|
||||||
label_export_options: "%{export_format} параметры экспорта"
|
label_export_options: "%{export_format} параметры экспорта"
|
||||||
error_attachment_too_big: Этот файл нельзя загрузить из-за превышения максимального размера файла (%{max_size})
|
error_attachment_too_big: Этот файл нельзя загрузить из-за превышения максимального размера файла (%{max_size})
|
||||||
notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}."
|
notice_failed_to_save_time_entries: "Невозможно сохранить %{count} затраченное время для %{total} выбранных: %{ids}."
|
||||||
label_x_issues:
|
label_x_issues:
|
||||||
zero: 0 Задач
|
zero: 0 Задач
|
||||||
one: 1 Задача
|
one: 1 Задача
|
||||||
@@ -1147,32 +1147,32 @@ ru:
|
|||||||
setting_unsubscribe: "Разрешить пользователям удалять свои учетные записи"
|
setting_unsubscribe: "Разрешить пользователям удалять свои учетные записи"
|
||||||
button_delete_my_account: "Удалить мою учетную запись"
|
button_delete_my_account: "Удалить мою учетную запись"
|
||||||
text_account_destroy_confirmation: "Ваша учетная запись будет полностью удалена без возможности восстановления.\nВы уверены, что хотите продолжить?"
|
text_account_destroy_confirmation: "Ваша учетная запись будет полностью удалена без возможности восстановления.\nВы уверены, что хотите продолжить?"
|
||||||
error_session_expired: Your session has expired. Please login again.
|
error_session_expired: Срок вашей сессии истек. Пожалуйста войдите еще раз
|
||||||
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
|
text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours."
|
||||||
setting_session_lifetime: Session maximum lifetime
|
setting_session_lifetime: Максимальная продолжительность сессии
|
||||||
setting_session_timeout: Session inactivity timeout
|
setting_session_timeout: Таймут сессии
|
||||||
label_session_expiration: Session expiration
|
label_session_expiration: Срок истечения сессии
|
||||||
permission_close_project: Close / reopen the project
|
permission_close_project: Закрывать / открывать проекты
|
||||||
label_show_closed_projects: View closed projects
|
label_show_closed_projects: Просматривать закрытые проекты
|
||||||
button_close: Close
|
button_close: Сделать закрытым
|
||||||
button_reopen: Reopen
|
button_reopen: Сделать открытым
|
||||||
project_status_active: active
|
project_status_active: открытые
|
||||||
project_status_closed: closed
|
project_status_closed: закрытые
|
||||||
project_status_archived: archived
|
project_status_archived: архивированные
|
||||||
text_project_closed: This project is closed and read-only.
|
text_project_closed: Проект закрыт и находиться в режиме только для чтения.
|
||||||
notice_user_successful_create: User %{id} created.
|
notice_user_successful_create: Пользователь %{id} создан.
|
||||||
field_core_fields: Standard fields
|
field_core_fields: Стандартные поля
|
||||||
field_timeout: Timeout (in seconds)
|
field_timeout: Таймаут (в секундах)
|
||||||
setting_thumbnails_enabled: Display attachment thumbnails
|
setting_thumbnails_enabled: Отображать превью для приложений
|
||||||
setting_thumbnails_size: Thumbnails size (in pixels)
|
setting_thumbnails_size: Размер первью (в пикселях)
|
||||||
label_status_transitions: Status transitions
|
label_status_transitions: Статус-переходы
|
||||||
label_fields_permissions: Fields permissions
|
label_fields_permissions: Права на изменения полей
|
||||||
label_readonly: Read-only
|
label_readonly: Не изменяется
|
||||||
label_required: Required
|
label_required: Обязательное
|
||||||
text_repository_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.<br />После сохранения идентификатор изменить нельзя.
|
text_repository_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.<br />После сохранения идентификатор изменить нельзя.
|
||||||
field_board_parent: Parent forum
|
field_board_parent: Родительский форум
|
||||||
label_attribute_of_project: Project's %{name}
|
label_attribute_of_project: Проект %{name}
|
||||||
label_attribute_of_author: Author's %{name}
|
label_attribute_of_author: Имя автора %{name}
|
||||||
label_attribute_of_assigned_to: Assignee's %{name}
|
label_attribute_of_assigned_to: Назначена %{name}
|
||||||
label_attribute_of_fixed_version: Target version's %{name}
|
label_attribute_of_fixed_version: Версия %{name}
|
||||||
label_copy_subtasks: Copy subtasks
|
label_copy_subtasks: Копировать подзадачи
|
||||||
|
|||||||
@@ -939,6 +939,7 @@
|
|||||||
label_child_revision: 子項
|
label_child_revision: 子項
|
||||||
label_export_options: "%{export_format} 匯出選項"
|
label_export_options: "%{export_format} 匯出選項"
|
||||||
label_copy_attachments: 複製附件
|
label_copy_attachments: 複製附件
|
||||||
|
label_copy_subtasks: 複製子任務
|
||||||
label_item_position: "%{position} / %{count}"
|
label_item_position: "%{position} / %{count}"
|
||||||
label_completed_versions: 已完成版本
|
label_completed_versions: 已完成版本
|
||||||
label_search_for_watchers: 搜尋可供加入的監看者
|
label_search_for_watchers: 搜尋可供加入的監看者
|
||||||
@@ -1143,4 +1144,3 @@
|
|||||||
description_date_from: 輸入起始日期
|
description_date_from: 輸入起始日期
|
||||||
description_date_to: 輸入結束日期
|
description_date_to: 輸入結束日期
|
||||||
text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。<br />一旦儲存之後, 代碼便無法再次被更改。'
|
text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。<br />一旦儲存之後, 代碼便無法再次被更改。'
|
||||||
label_copy_subtasks: Copy subtasks
|
|
||||||
|
|||||||
@@ -1061,9 +1061,9 @@ zh:
|
|||||||
label_readonly: 只读
|
label_readonly: 只读
|
||||||
label_required: 必填
|
label_required: 必填
|
||||||
text_repository_identifier_info: 仅小写字母(a-z)、数字、破折号(-)和下划线(_)可以使用。<br />一旦保存,标识无法修改。
|
text_repository_identifier_info: 仅小写字母(a-z)、数字、破折号(-)和下划线(_)可以使用。<br />一旦保存,标识无法修改。
|
||||||
field_board_parent: Parent forum
|
field_board_parent: 父论坛
|
||||||
label_attribute_of_project: Project's %{name}
|
label_attribute_of_project: 项目 %{name}
|
||||||
label_attribute_of_author: Author's %{name}
|
label_attribute_of_author: 作者 %{name}
|
||||||
label_attribute_of_assigned_to: Assignee's %{name}
|
label_attribute_of_assigned_to: 分配给 %{name}
|
||||||
label_attribute_of_fixed_version: Target version's %{name}
|
label_attribute_of_fixed_version: 目标版本 %{name}
|
||||||
label_copy_subtasks: Copy subtasks
|
label_copy_subtasks: 复制子任务
|
||||||
|
|||||||
+163
@@ -4,6 +4,169 @@ Redmine - project management software
|
|||||||
Copyright (C) 2006-2012 Jean-Philippe Lang
|
Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||||
http://www.redmine.org/
|
http://www.redmine.org/
|
||||||
|
|
||||||
|
== 2013-01-09 v2.1.6
|
||||||
|
|
||||||
|
* Upgrade to Rails 3.2.11
|
||||||
|
|
||||||
|
== 2012-12-18 v2.1.5
|
||||||
|
|
||||||
|
* Defect #12400: Validation fails when receiving an email with list custom fields
|
||||||
|
* Defect #12451: Macros.rb extract_macro_options should use lazy search
|
||||||
|
* Defect #12513: Grouping of issues by custom fields not correct in PDF export
|
||||||
|
* Defect #12566: Issue history notes previews are broken
|
||||||
|
* Defect #12568: Clicking "edit" on a journal multiple times shows multiple forms
|
||||||
|
* Patch #12605: Norwegian translation for 1.4-stable update
|
||||||
|
* Patch #12614: Dutch translation
|
||||||
|
* Patch #12615: Russian translation
|
||||||
|
|
||||||
|
== 2012-11-24 v2.1.4
|
||||||
|
|
||||||
|
* Defect #12274: Wiki export from Index by title is truncated
|
||||||
|
* Defect #12298: Right-click context menu unable to batch/bulk update (IE8)
|
||||||
|
* Defect #12332: Repository identifier does not display on Project/Settings/Repositories
|
||||||
|
* Defect #12396: Error when receiving an email without subject header
|
||||||
|
* Defect #12399: Non ASCII attachment filename encoding broken (MOJIBAKE) in receiving mail on Ruby 1.8
|
||||||
|
* Defect #12409: Git: changesets aren't read after clear_changesets call
|
||||||
|
* Defect #12431: Project.rebuild! sorts root projects by id instead of name
|
||||||
|
|
||||||
|
== 2012-11-17 v2.1.3
|
||||||
|
|
||||||
|
* Defect #12050: :export links to repository files lead to a 404 error
|
||||||
|
* Defect #12189: Missing tmp/pdf directory
|
||||||
|
* Defect #12195: Javascript error with IE7 / IE8 on new issue form
|
||||||
|
* Defect #12196: "Page not found" on OK button in SCM "View all revisions" page
|
||||||
|
* Defect #12199: Confirmation message displayed when clicking a disabled delete link in the context menu
|
||||||
|
* Defect #12231: Hardcoded "Back" in Repository
|
||||||
|
* Defect #12294: Incorrect german translation for "registered" users filter
|
||||||
|
* Defect #12349: Watchers auto-complete search on non-latin chars
|
||||||
|
* Defect #12358: 'None' grouped issue list section should be translated
|
||||||
|
* Defect #12359: Version date field regex validation accepts invalid date
|
||||||
|
* Defect #12375: Receiving mail subject encoding broken (MOJIBAKE) in some cases on Ruby 1.8
|
||||||
|
* Patch #9732: German translations
|
||||||
|
* Patch #12021: Russian locale translations
|
||||||
|
* Patch #12188: Simplified Chinese translation with zh.yml file based on Rev:10681
|
||||||
|
* Patch #12235: German translation for 2.1-stable
|
||||||
|
* Patch #12237: Added German Translation
|
||||||
|
|
||||||
|
== 2012-09-30 v2.1.2
|
||||||
|
|
||||||
|
* Defect #11929: XSS vulnerability in Redmine 2.1.x
|
||||||
|
|
||||||
|
== 2012-09-30 v2.1.1
|
||||||
|
|
||||||
|
* Defect #11290: ParseDate missing in Ruby 1.9x
|
||||||
|
* Defect #11844: "load_default_data" rake task fails to print the error message if one occurs
|
||||||
|
* Defect #11850: Can't create a user from ldap by on-the-fly on the redmine server using URI prefix
|
||||||
|
* Defect #11872: Private issue visible to anonymous users after its author is deleted
|
||||||
|
* Defect #11885: Filter misses Selectionfield on IE8
|
||||||
|
* Defect #11893: New relation form Cancel link is broken with Chrome 21
|
||||||
|
* Defect #11905: Potential "can't dup NilClass" error in UserPreference
|
||||||
|
* Defect #11909: Autocomplete results not reset after clearing search field
|
||||||
|
* Defect #11922: bs.yml and de.yml lead to error by number_to_currency()
|
||||||
|
* Defect #11945: rake task prints "can't convert Errno::EACCES into String" in case of no permission of public/plugin_assets
|
||||||
|
* Defect #11975: Undefined status transitions allowed in workflow (author of issue changes when selecting a new status)
|
||||||
|
* Defect #11982: SCM diff view generates extra parameter for switching mode
|
||||||
|
* Patch #11897: Traditional Chinese language file (to r10433)
|
||||||
|
|
||||||
|
== 2012-09-16 v2.1.0
|
||||||
|
|
||||||
|
* Defect #2071: Reordering priority-enumerations breaks alternate-theme's issue-colouring
|
||||||
|
* Defect #2190: Month names not translated to german
|
||||||
|
* Defect #8978: LDAP timeout if an LDAP auth provider is unreachable
|
||||||
|
* Defect #9839: Gantt abbr of weekday should not be necessarily the first letter of the long day name
|
||||||
|
* Defect #10928: Documentation about generating a plugin is not up-to-date
|
||||||
|
* Defect #11034: TLS configuration documentation for Rails 3
|
||||||
|
* Defect #11073: UserCustomField order_statement returns wrong output
|
||||||
|
* Defect #11153: Default sorting for target version is DESC instead of ASC
|
||||||
|
* Defect #11207: Issues associated with a locked version are not copied when copying a project
|
||||||
|
* Defect #11304: Issue-class: status-1, status-2 etc. refer to status position instead of status id
|
||||||
|
* Defect #11331: Openid registration form should not require user to enter password
|
||||||
|
* Defect #11345: Context menu should show shared versions when editing issues from different projects
|
||||||
|
* Defect #11355: Plain text notification emails content is HTML escaped
|
||||||
|
* Defect #11388: Updating a version through rest API returns invalid JSON
|
||||||
|
* Defect #11389: Warning in awesome_nested_set.rb
|
||||||
|
* Defect #11503: Accessing /projects/:project/wiki/something.png fails with error 500
|
||||||
|
* Defect #11506: Versions that are not shared should not be assignable when selecting another project
|
||||||
|
* Defect #11508: Projects not ordered alphabetically after renaming project
|
||||||
|
* Defect #11540: Roadmap anchor links can be ambigous
|
||||||
|
* Defect #11545: Overwriting existing method Issue.open
|
||||||
|
* Defect #11552: MailHandler does not match assignee name with spaces
|
||||||
|
* Defect #11571: Custom fields of type version not proper handled in receiving e-mails
|
||||||
|
* Defect #11577: Can't use non-latin anchor in wiki
|
||||||
|
* Defect #11612: Revision graph sometimes broken due to raphael.js error
|
||||||
|
* Defect #11621: Redmine MIME Detection Of Javascript Files Non-Standard
|
||||||
|
* Defect #11633: Macro arguments should not be parsed by text formatters
|
||||||
|
* Defect #11662: Invalid query returned from Issues.visible scope after accessing User#projects_by_role with a role that is not present
|
||||||
|
* Defect #11691: 404 response when deleting a user from the edit page
|
||||||
|
* Defect #11723: redmine:send_reminders notification misses if assignee is a group
|
||||||
|
* Defect #11738: Batch update of issues clears project path
|
||||||
|
* Defect #11749: Redmine.pm: HEAD is not considered as a read-only method
|
||||||
|
* Defect #11814: Date picker does not respect week start setting
|
||||||
|
* Feature #703: Configurable required fields per tracker/status/role
|
||||||
|
* Feature #1006: Display thumbnails of attached images
|
||||||
|
* Feature #1091: Disabling default ticket fields per tracker
|
||||||
|
* Feature #1360: Permission for adding an issue to a version.
|
||||||
|
* Feature #3061: Let macros optionally match over multiple lines and ignore single curly braces
|
||||||
|
* Feature #3510: Inserting image thumbnails inside the wiki
|
||||||
|
* Feature #3521: Permissions for roles to change fields per tracker/status
|
||||||
|
* Feature #3640: Freeze / Close Projects
|
||||||
|
* Feature #3831: Support for subforums
|
||||||
|
* Feature #6597: Configurable session lifetime and timeout
|
||||||
|
* Feature #6965: Option to Copy Subtasks when copying an issue
|
||||||
|
* Feature #8161: Ability to filter issues on project custom fields
|
||||||
|
* Feature #8577: "Private" column and filter on the issue list
|
||||||
|
* Feature #8981: REST Api for Groups
|
||||||
|
* Feature #9258: Create role by copy
|
||||||
|
* Feature #9419: Group/sort the issue list by user/version-format custom fields
|
||||||
|
* Feature #10362: Show images in repositories inline when clicking the 'View' link
|
||||||
|
* Feature #10419: Upgrade raphael.js (2.1.0)
|
||||||
|
* Feature #11068: Ability to set default column order in issue list
|
||||||
|
* Feature #11102: Add autocomplete to "Related issue" field on revision
|
||||||
|
* Feature #11109: Repository Identifier should be frozen
|
||||||
|
* Feature #11181: Additional "Log time" link on project overview
|
||||||
|
* Feature #11205: Reversed order of priorities on the issue summary page
|
||||||
|
* Feature #11445: Switch from Prototype to JQuery
|
||||||
|
* Feature #11469: JSONP support
|
||||||
|
* Feature #11475: Redmine.pm: Allow fallback to other Apache auth providers
|
||||||
|
* Feature #11494: Don't turn #nnn with leading zeros into links
|
||||||
|
* Feature #11539: Display a projects tree instead of a flat list in notification preferences
|
||||||
|
* Feature #11578: Option to pass whole arguments to a macro without splitting them
|
||||||
|
* Feature #11595: Missing mime type for svg files
|
||||||
|
* Feature #11758: Upgrade to Rails 3.2.8
|
||||||
|
* Patch #4905: Redmine.pm: add support for Git's smart HTTP protocol
|
||||||
|
* Patch #10988: New Korean translation patch
|
||||||
|
* Patch #11201: Korean translation special update
|
||||||
|
* Patch #11401: Fix Japanese mistranslation for "button_submit"
|
||||||
|
* Patch #11402: Japanese translation added for default role names
|
||||||
|
* Patch #11411: Fix disordered use of long sound in Japanese "user" translation
|
||||||
|
* Patch #11412: Unnatural Japanese message when users failed to login
|
||||||
|
* Patch #11419: Fix wrong Japanese "label_attachment" translation
|
||||||
|
* Patch #11496: Make labels clickable in Adminstration/Settings
|
||||||
|
* Patch #11704: Avoid the use of tag("...", "...", true) in layout
|
||||||
|
* Patch #11818: Redmine.pm fails when permissions are NULL
|
||||||
|
|
||||||
|
== 2012-09-16 v2.0.4
|
||||||
|
|
||||||
|
* Defect #10818: Running rake in test environment causes exception
|
||||||
|
* Defect #11209: Wiki diff may generate broken HTML
|
||||||
|
* Defect #11217: Project names in drop-down are escaped twice
|
||||||
|
* Defect #11262: Link is escaped in wiki added/updated notification email
|
||||||
|
* Defect #11307: Can't filter for negative numeric custom fields
|
||||||
|
* Defect #11325: Unified diff link broken on specific file/revision diff view
|
||||||
|
* Defect #11341: Escaped link in conflict resolution form
|
||||||
|
* Defect #11365: Attachment description length is not validated
|
||||||
|
* Defect #11511: Confirmation page has broken HTML when a project folding sub project is deleted
|
||||||
|
* Defect #11533: rake redmine:plugins:test doesn't run tests in subdirectories
|
||||||
|
* Defect #11541: Version sharing is missing in the REST API
|
||||||
|
* Defect #11550: Issue reminder doesn't work when using asynchronous delivery
|
||||||
|
* Defect #11776: Can't override mailer views inside redmine plugin.
|
||||||
|
* Defect #11789: Edit section links broken with h5/h6 headings
|
||||||
|
* Feature #11338: Exclude emails with auto-submitted => auto-generated
|
||||||
|
* Patch #11299: redmine:plugins:migrate should update db/schema.rb
|
||||||
|
* Patch #11328: Fix Japanese mistranslation for 'label_language_based'
|
||||||
|
* Patch #11448: Russian translation for 1.4-stable and 2.0-stable
|
||||||
|
* Patch #11600: Fix plural form of the abbreviation for hours in Brazilian Portuguese
|
||||||
|
|
||||||
== 2012-06-18 v2.0.3
|
== 2012-06-18 v2.0.3
|
||||||
|
|
||||||
* Defect #10688: PDF export from Wiki - Problems with tables
|
* Defect #10688: PDF export from Wiki - Problems with tables
|
||||||
|
|||||||
+5
-2
@@ -13,7 +13,7 @@ http://www.redmine.org/
|
|||||||
|
|
||||||
* A database:
|
* A database:
|
||||||
* MySQL (tested with MySQL 5.1)
|
* MySQL (tested with MySQL 5.1)
|
||||||
* PostgreSQL (tested with PostgreSQL 8.4)
|
* PostgreSQL (tested with PostgreSQL 9.1)
|
||||||
* SQLite3 (tested with SQLite 3.6)
|
* SQLite3 (tested with SQLite 3.6)
|
||||||
|
|
||||||
Optional:
|
Optional:
|
||||||
@@ -38,7 +38,10 @@ Optional:
|
|||||||
3. Create an empty utf8 encoded database: "redmine" for example
|
3. Create an empty utf8 encoded database: "redmine" for example
|
||||||
|
|
||||||
4. Configure the database parameters in config/database.yml
|
4. Configure the database parameters in config/database.yml
|
||||||
for the "production" environment (default database is MySQL)
|
for the "production" environment (default database is MySQL and ruby1.8)
|
||||||
|
|
||||||
|
If you're running Redmine with MySQL and ruby1.9, replace the adapter name
|
||||||
|
with `mysql2`
|
||||||
|
|
||||||
5. Generate a session store secret
|
5. Generate a session store secret
|
||||||
|
|
||||||
|
|||||||
@@ -249,7 +249,8 @@ sub RedmineDSN {
|
|||||||
roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
|
roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
|
||||||
OR
|
OR
|
||||||
(roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
|
(roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
|
||||||
) ";
|
)
|
||||||
|
AND roles.permissions IS NOT NULL";
|
||||||
$self->{RedmineQuery} = trim($query);
|
$self->{RedmineQuery} = trim($query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
require 'SVG/Graph/Plot'
|
require 'SVG/Graph/Plot'
|
||||||
require 'parsedate'
|
|
||||||
|
|
||||||
module SVG
|
module SVG
|
||||||
module Graph
|
module Graph
|
||||||
@@ -157,8 +156,7 @@ module SVG
|
|||||||
y = []
|
y = []
|
||||||
data[:data].each_index {|i|
|
data[:data].each_index {|i|
|
||||||
if i%2 == 0
|
if i%2 == 0
|
||||||
arr = ParseDate.parsedate( data[:data][i] )
|
t = DateTime.parse( data[:data][i] ).to_time
|
||||||
t = Time.local( *arr[0,6].compact )
|
|
||||||
x << t.to_i
|
x << t.to_i
|
||||||
else
|
else
|
||||||
y << data[:data][i]
|
y << data[:data][i]
|
||||||
@@ -173,8 +171,7 @@ module SVG
|
|||||||
protected
|
protected
|
||||||
|
|
||||||
def min_x_value=(value)
|
def min_x_value=(value)
|
||||||
arr = ParseDate.parsedate( value )
|
@min_x_value = DateTime.parse( data[:data][i] ).to_time
|
||||||
@min_x_value = Time.local( *arr[0,6].compact ).to_i
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ module Redmine
|
|||||||
attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
|
attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
|
||||||
|
|
||||||
has_many :attachments, options.merge(:as => :container,
|
has_many :attachments, options.merge(:as => :container,
|
||||||
:order => "#{Attachment.table_name}.created_on",
|
:order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC",
|
||||||
:dependent => :destroy)
|
:dependent => :destroy)
|
||||||
send :include, Redmine::Acts::Attachable::InstanceMethods
|
send :include, Redmine::Acts::Attachable::InstanceMethods
|
||||||
before_save :attach_saved_attachments
|
before_save :attach_saved_attachments
|
||||||
@@ -62,7 +62,19 @@ module Redmine
|
|||||||
|
|
||||||
def save_attachments(attachments, author=User.current)
|
def save_attachments(attachments, author=User.current)
|
||||||
if attachments.is_a?(Hash)
|
if attachments.is_a?(Hash)
|
||||||
attachments = attachments.values
|
attachments = attachments.stringify_keys
|
||||||
|
attachments = attachments.to_a.sort {|a, b|
|
||||||
|
if a.first.to_i > 0 && b.first.to_i > 0
|
||||||
|
a.first.to_i <=> b.first.to_i
|
||||||
|
elsif a.first.to_i > 0
|
||||||
|
1
|
||||||
|
elsif b.first.to_i > 0
|
||||||
|
-1
|
||||||
|
else
|
||||||
|
a.first <=> b.first
|
||||||
|
end
|
||||||
|
}
|
||||||
|
attachments = attachments.map(&:last)
|
||||||
end
|
end
|
||||||
if attachments.is_a?(Array)
|
if attachments.is_a?(Array)
|
||||||
attachments.each do |attachment|
|
attachments.each do |attachment|
|
||||||
|
|||||||
@@ -186,7 +186,7 @@ module CollectiveIdea #:nodoc:
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Find root node(s)
|
# Find root node(s)
|
||||||
root_nodes = where("#{quoted_parent_column_name} IS NULL").order("#{quoted_left_column_name}, #{quoted_right_column_name}, id").each do |root_node|
|
root_nodes = where("#{quoted_parent_column_name} IS NULL").order(acts_as_nested_set_options[:order]).each do |root_node|
|
||||||
# setup index for this scope
|
# setup index for this scope
|
||||||
indices[scope.call(root_node)] ||= 0
|
indices[scope.call(root_node)] ||= 0
|
||||||
set_left_and_rights.call(root_node)
|
set_left_and_rights.call(root_node)
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ module Redmine
|
|||||||
if query.grouped? &&
|
if query.grouped? &&
|
||||||
(group = query.group_by_column.value(issue)) != previous_group
|
(group = query.group_by_column.value(issue)) != previous_group
|
||||||
pdf.SetFontStyle('B',10)
|
pdf.SetFontStyle('B',10)
|
||||||
group_label = group.blank? ? 'None' : group.to_s
|
group_label = group.blank? ? 'None' : group.to_s.dup
|
||||||
group_label << " (#{query.issue_count_by_group[group]})"
|
group_label << " (#{query.issue_count_by_group[group]})"
|
||||||
pdf.Bookmark group_label, 0, -1
|
pdf.Bookmark group_label, 0, -1
|
||||||
pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L')
|
pdf.RDMCell(table_width + col_id_width, row_height * 2, group_label, 1, 1, 'L')
|
||||||
|
|||||||
@@ -336,7 +336,11 @@ module Redmine #:nodoc:
|
|||||||
|
|
||||||
unless source_files.empty?
|
unless source_files.empty?
|
||||||
base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
|
base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
|
||||||
FileUtils.mkdir_p(base_target_dir)
|
begin
|
||||||
|
FileUtils.mkdir_p(base_target_dir)
|
||||||
|
rescue Exception => e
|
||||||
|
raise "Could not create directory #{base_target_dir}: " + e.message
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
source_dirs.each do |dir|
|
source_dirs.each do |dir|
|
||||||
@@ -346,7 +350,7 @@ module Redmine #:nodoc:
|
|||||||
begin
|
begin
|
||||||
FileUtils.mkdir_p(target_dir)
|
FileUtils.mkdir_p(target_dir)
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise "Could not create directory #{target_dir}: \n" + e
|
raise "Could not create directory #{target_dir}: " + e.message
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -357,7 +361,7 @@ module Redmine #:nodoc:
|
|||||||
FileUtils.cp(file, target)
|
FileUtils.cp(file, target)
|
||||||
end
|
end
|
||||||
rescue Exception => e
|
rescue Exception => e
|
||||||
raise "Could not copy #{file} to #{target}: \n" + e
|
raise "Could not copy #{file} to #{target}: " + e.message
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ module Redmine
|
|||||||
module VERSION #:nodoc:
|
module VERSION #:nodoc:
|
||||||
MAJOR = 2
|
MAJOR = 2
|
||||||
MINOR = 1
|
MINOR = 1
|
||||||
TINY = 0
|
TINY = 6
|
||||||
|
|
||||||
# Branch values:
|
# Branch values:
|
||||||
# * official release: nil
|
# * official release: nil
|
||||||
# * stable branch: stable
|
# * stable branch: stable
|
||||||
# * trunk: devel
|
# * trunk: devel
|
||||||
BRANCH = 'devel'
|
BRANCH = 'stable'
|
||||||
|
|
||||||
def self.revision
|
def self.revision
|
||||||
revision = nil
|
revision = nil
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ module Redmine
|
|||||||
|
|
||||||
def extract_macro_options(args, *keys)
|
def extract_macro_options(args, *keys)
|
||||||
options = {}
|
options = {}
|
||||||
while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym)
|
while args.last.to_s.strip =~ %r{^(.+?)\=(.+)$} && keys.include?($1.downcase.to_sym)
|
||||||
options[$1.downcase.to_sym] = $2
|
options[$1.downcase.to_sym] = $2
|
||||||
args.pop
|
args.pop
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ namespace :redmine do
|
|||||||
Redmine::DefaultData::Loader.load(current_language)
|
Redmine::DefaultData::Loader.load(current_language)
|
||||||
puts "Default configuration data loaded."
|
puts "Default configuration data loaded."
|
||||||
rescue Redmine::DefaultData::DataAlreadyLoaded => error
|
rescue Redmine::DefaultData::DataAlreadyLoaded => error
|
||||||
puts error
|
puts error.message
|
||||||
rescue => error
|
rescue => error
|
||||||
puts "Error: " + error
|
puts "Error: " + error.message
|
||||||
puts "Default configuration data was not loaded."
|
puts "Default configuration data was not loaded."
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -152,10 +152,10 @@ function buildFilterRow(field, operator, values) {
|
|||||||
var option = $('<option>');
|
var option = $('<option>');
|
||||||
if ($.isArray(filterValue)) {
|
if ($.isArray(filterValue)) {
|
||||||
option.val(filterValue[1]).text(filterValue[0]);
|
option.val(filterValue[1]).text(filterValue[0]);
|
||||||
if (values.indexOf(filterValue[1]) > -1) {option.attr('selected', true)};
|
if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
|
||||||
} else {
|
} else {
|
||||||
option.val(filterValue).text(filterValue);
|
option.val(filterValue).text(filterValue);
|
||||||
if (values.indexOf(filterValue) > -1) {option.attr('selected', true)};
|
if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
|
||||||
}
|
}
|
||||||
select.append(option);
|
select.append(option);
|
||||||
}
|
}
|
||||||
@@ -163,9 +163,9 @@ function buildFilterRow(field, operator, values) {
|
|||||||
case "date":
|
case "date":
|
||||||
case "date_past":
|
case "date_past":
|
||||||
tr.find('td.values').append(
|
tr.find('td.values').append(
|
||||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" value="'+values[0]+'" /></span>' +
|
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" /></span>' +
|
||||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" value="'+values[1]+'" /></span>' +
|
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" /></span>' +
|
||||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" value="'+values[0]+'" /> '+labelDayPlural+'</span>'
|
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" /> '+labelDayPlural+'</span>'
|
||||||
);
|
);
|
||||||
$('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
|
$('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
|
||||||
$('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
|
$('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
|
||||||
@@ -174,15 +174,15 @@ function buildFilterRow(field, operator, values) {
|
|||||||
case "string":
|
case "string":
|
||||||
case "text":
|
case "text":
|
||||||
tr.find('td.values').append(
|
tr.find('td.values').append(
|
||||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" value="'+values[0]+'" /></span>'
|
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" /></span>'
|
||||||
);
|
);
|
||||||
$('#values_'+fieldId).val(values[0]);
|
$('#values_'+fieldId).val(values[0]);
|
||||||
break;
|
break;
|
||||||
case "integer":
|
case "integer":
|
||||||
case "float":
|
case "float":
|
||||||
tr.find('td.values').append(
|
tr.find('td.values').append(
|
||||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" value="'+values[0]+'" /></span>' +
|
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" /></span>' +
|
||||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" value="'+values[1]+'" /></span>'
|
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" /></span>'
|
||||||
);
|
);
|
||||||
$('#values_'+fieldId+'_1').val(values[0]);
|
$('#values_'+fieldId+'_1').val(values[0]);
|
||||||
$('#values_'+fieldId+'_2').val(values[1]);
|
$('#values_'+fieldId+'_2').val(values[1]);
|
||||||
@@ -204,7 +204,7 @@ function toggleFilter(field) {
|
|||||||
function enableValues(field, indexes) {
|
function enableValues(field, indexes) {
|
||||||
var fieldId = field.replace('.', '_');
|
var fieldId = field.replace('.', '_');
|
||||||
$('#tr_'+fieldId+' td.values .value').each(function(index) {
|
$('#tr_'+fieldId+' td.values .value').each(function(index) {
|
||||||
if (indexes.indexOf(index) >= 0) {
|
if ($.inArray(index, indexes) >= 0) {
|
||||||
$(this).removeAttr('disabled');
|
$(this).removeAttr('disabled');
|
||||||
$(this).parents('span').first().show();
|
$(this).parents('span').first().show();
|
||||||
} else {
|
} else {
|
||||||
@@ -464,9 +464,11 @@ function updateBulkEditFrom(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function observeAutocompleteField(fieldId, url) {
|
function observeAutocompleteField(fieldId, url) {
|
||||||
$('#'+fieldId).autocomplete({
|
$(document).ready(function() {
|
||||||
source: url,
|
$('#'+fieldId).autocomplete({
|
||||||
minLength: 2,
|
source: url,
|
||||||
|
minLength: 2
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,16 +480,14 @@ function observeSearchfield(fieldId, targetId, url) {
|
|||||||
var val = $this.val();
|
var val = $this.val();
|
||||||
if ($this.attr('data-value-was') != val){
|
if ($this.attr('data-value-was') != val){
|
||||||
$this.attr('data-value-was', val);
|
$this.attr('data-value-was', val);
|
||||||
if (val != '') {
|
$.ajax({
|
||||||
$.ajax({
|
url: url,
|
||||||
url: url,
|
type: 'get',
|
||||||
type: 'get',
|
data: {q: $this.val()},
|
||||||
data: {q: $this.val()},
|
success: function(data){ $('#'+targetId).html(data); },
|
||||||
success: function(data){ $('#'+targetId).html(data); },
|
beforeSend: function(){ $this.addClass('ajax-loading'); },
|
||||||
beforeSend: function(){ $this.addClass('ajax-loading'); },
|
complete: function(){ $this.removeClass('ajax-loading'); }
|
||||||
complete: function(){ $this.removeClass('ajax-loading'); }
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
var reset = function() {
|
var reset = function() {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function contextMenuClick(event) {
|
|||||||
}
|
}
|
||||||
contextMenuHide();
|
contextMenuHide();
|
||||||
if (target.is('a') || target.is('img')) { return; }
|
if (target.is('a') || target.is('img')) { return; }
|
||||||
if (event.which == 1 /*TODO || (navigator.appVersion.match(/\bMSIE\b/))*/) {
|
if (event.which == 1 || (navigator.appVersion.match(/\bMSIE\b/))) {
|
||||||
var tr = target.parents('tr').first();
|
var tr = target.parents('tr').first();
|
||||||
if (tr.length && tr.hasClass('hascontextmenu')) {
|
if (tr.length && tr.hasClass('hascontextmenu')) {
|
||||||
// a row was clicked, check if the click was on checkbox
|
// a row was clicked, check if the click was on checkbox
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -35,6 +35,9 @@ function drawRevisionGraph(holder, commits_hash, graph_space) {
|
|||||||
var path, title;
|
var path, title;
|
||||||
var revision_dot_overlay;
|
var revision_dot_overlay;
|
||||||
$.each(commits, function(index, commit) {
|
$.each(commits, function(index, commit) {
|
||||||
|
if (!commit.hasOwnProperty("space"))
|
||||||
|
commit.space = 0;
|
||||||
|
|
||||||
y = commit_table_rows.eq(max_rdmid - commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
y = commit_table_rows.eq(max_rdmid - commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
||||||
x = graph_x_offset + XSTEP / 2 + XSTEP * commit.space;
|
x = graph_x_offset + XSTEP / 2 + XSTEP * commit.space;
|
||||||
revisionGraph.circle(x, y, 3)
|
revisionGraph.circle(x, y, 3)
|
||||||
@@ -46,6 +49,9 @@ function drawRevisionGraph(holder, commits_hash, graph_space) {
|
|||||||
$.each(commit.parent_scmids, function(index, parent_scmid) {
|
$.each(commit.parent_scmids, function(index, parent_scmid) {
|
||||||
parent_commit = commits_by_scmid[parent_scmid];
|
parent_commit = commits_by_scmid[parent_scmid];
|
||||||
if (parent_commit) {
|
if (parent_commit) {
|
||||||
|
if (!parent_commit.hasOwnProperty("space"))
|
||||||
|
parent_commit.space = 0;
|
||||||
|
|
||||||
parent_y = commit_table_rows.eq(max_rdmid - parent_commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
parent_y = commit_table_rows.eq(max_rdmid - parent_commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
||||||
parent_x = graph_x_offset + XSTEP / 2 + XSTEP * parent_commit.space;
|
parent_x = graph_x_offset + XSTEP / 2 + XSTEP * parent_commit.space;
|
||||||
if (parent_commit.space == commit.space) {
|
if (parent_commit.space == commit.space) {
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
Date: Tue, 20 Nov 2012 23:08:25 +0900
|
||||||
|
Message-ID: <CANBr5-UZM=Odz4U3Q6vHd_9cd2tCT-_P9xDd=hRJ0aoMNTWXbw@mail.gmail.com>
|
||||||
|
Subject: test
|
||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
To: redmine@somenet.foo
|
||||||
|
Content-Type: multipart/mixed; boundary=14dae93a13bf76ca5d04ceedc458
|
||||||
|
|
||||||
|
--14dae93a13bf76ca5d04ceedc458
|
||||||
|
Content-Type: text/plain; charset=ISO-8859-1
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--14dae93a13bf76ca5d04ceedc458
|
||||||
|
Content-Type: text/plain; charset=US-ASCII;
|
||||||
|
name="=?ISO-8859-1?B?xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tw=?=
|
||||||
|
=?ISO-8859-1?B?/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc?=
|
||||||
|
=?ISO-8859-1?B?/MTk1vbc/C50eHQ=?="
|
||||||
|
Content-Disposition: attachment;
|
||||||
|
filename="=?ISO-8859-1?B?xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tz8xOTW9tw=?=
|
||||||
|
=?ISO-8859-1?B?/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc/MTk1vbc?=
|
||||||
|
=?ISO-8859-1?B?/MTk1vbc/C50eHQ=?="
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
X-Attachment-Id: f_h9r3mcjz0
|
||||||
|
|
||||||
|
dGVzdAo=
|
||||||
|
--14dae93a13bf76ca5d04ceedc458--
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
Date: Mon, 19 Nov 2012 10:17:45 +0900
|
||||||
|
Message-ID: <CANBr5-U6cXMfLek5QiB2ZrBPR3vTThn9_Upvdkf3Dkod664+Xw@mail.gmail.com>
|
||||||
|
Subject: test
|
||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
To: redmine@somenet.foo
|
||||||
|
Content-Type: multipart/mixed; boundary=bcaec54ee4ea84f77904cecee22e
|
||||||
|
|
||||||
|
--bcaec54ee4ea84f77904cecee22e
|
||||||
|
Content-Type: text/plain; charset=ISO-8859-1
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--bcaec54ee4ea84f77904cecee22e
|
||||||
|
Content-Type: text/plain; charset=US-ASCII; name="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?="
|
||||||
|
Content-Disposition: attachment; filename="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?="
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
X-Attachment-Id: f_h9owndpv0
|
||||||
|
|
||||||
|
dGVzdAo=
|
||||||
|
--bcaec54ee4ea84f77904cecee22e--
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
Content-Type: application/ms-tnef; name="winmail.dat"
|
||||||
|
Content-Transfer-Encoding: binary
|
||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
To: "redmine@somenet.foo" <redmine@somenet.foo>
|
||||||
|
Date: Fri, 1 Jun 2012 14:39:38 +0200
|
||||||
|
Message-ID: <87C31D42249DD0489D1A1444E3232DD7019D6183@foo.bar>
|
||||||
|
Accept-Language: de-CH, en-US
|
||||||
|
Content-Language: de-CH
|
||||||
|
|
||||||
|
Fixture
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
To: "redmine@somenet.foo" <redmine@somenet.foo>
|
||||||
|
Subject: =?iso-2022-jp?b?GyRCJUYlOSVIGyhCCg=?=
|
||||||
|
Date: Fri, 1 Jun 2012 14:39:38 +0200
|
||||||
|
Message-ID: <87C31D42249DD0489D1A1444E3232DD7019D6183@foo.bar>
|
||||||
|
|
||||||
|
Fixture
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
To: "redmine@somenet.foo" <redmine@somenet.foo>
|
||||||
|
Subject: Re: =?iso-2022-jp?b?GyRCJUYlOSVIGyhCCg=?=
|
||||||
|
Date: Fri, 1 Jun 2012 14:39:38 +0200
|
||||||
|
Message-ID: <87C31D42249DD0489D1A1444E3232DD7019D6183@foo.bar>
|
||||||
|
|
||||||
|
Fixture
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
Message-ID: <50AB9546.7020800@gmail.com>
|
||||||
|
Date: Tue, 20 Nov 2012 23:35:50 +0900
|
||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc13 Thunderbird/3.1.10
|
||||||
|
MIME-Version: 1.0
|
||||||
|
To: redmine@somenet.foo
|
||||||
|
Subject: test
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary="------------050902080306030406090208"
|
||||||
|
|
||||||
|
This is a multi-part message in MIME format.
|
||||||
|
--------------050902080306030406090208
|
||||||
|
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--------------050902080306030406090208
|
||||||
|
Content-Type: image/png;
|
||||||
|
name="=?ISO-8859-1?Q?=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4?=
|
||||||
|
=?ISO-8859-1?Q?=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6?=
|
||||||
|
=?ISO-8859-1?Q?=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6=DC=FC=C4=E4=D6=F6?=
|
||||||
|
=?ISO-8859-1?Q?=DC=FC=C4=E4=D6=F6=DC=FC=2Epng?="
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Disposition: attachment;
|
||||||
|
filename*0*=ISO-8859-1''%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6;
|
||||||
|
filename*1*=%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC;
|
||||||
|
filename*2*=%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%C4%E4;
|
||||||
|
filename*3*=%D6%F6%DC%FC%C4%E4%D6%F6%DC%FC%2E%70%6E%67
|
||||||
|
|
||||||
|
iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAIAAAACDbGyAAAAAXNSR0IArs4c6QAAAAlwSFlz
|
||||||
|
AAALEwAACxMBAJqcGAAAAAd0SU1FB9wLFA4fJhRKIUQAAAAUSURBVAjXY/z//z8DEmBiQAWk
|
||||||
|
8gHq9gMHP8uZWAAAAABJRU5ErkJggg==
|
||||||
|
--------------050902080306030406090208--
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
Message-ID: <50AA00C6.4070108@gmail.com>
|
||||||
|
Date: Mon, 19 Nov 2012 18:49:58 +0900
|
||||||
|
From: John Smith <JSmith@somenet.foo>
|
||||||
|
User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.1.15) Gecko/20101027 Fedora/3.0.10-1.fc12 Lightning/1.0b1 Thunderbird/3.0.10
|
||||||
|
MIME-Version: 1.0
|
||||||
|
To: redmine@somenet.foo
|
||||||
|
Subject: test
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary="------------030104060902010800050907"
|
||||||
|
|
||||||
|
This is a multi-part message in MIME format.
|
||||||
|
--------------030104060902010800050907
|
||||||
|
Content-Type: text/plain; charset=ISO-2022-JP
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
--------------030104060902010800050907
|
||||||
|
Content-Type: text/plain;
|
||||||
|
name="=?ISO-2022-JP?B?GyRCJUYlOSVIGyhCLnR4dA==?="
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
Content-Disposition: attachment;
|
||||||
|
filename*=ISO-2022-JP''%1B%24%42%25%46%25%39%25%48%1B%28%42%2E%74%78%74
|
||||||
|
|
||||||
|
dGVzdAo=
|
||||||
|
--------------030104060902010800050907--
|
||||||
@@ -39,3 +39,4 @@ pulvinar dui, a gravida orci mi eget odio. Nunc a lacus.
|
|||||||
|
|
||||||
category: Stock management
|
category: Stock management
|
||||||
searchable field: Value for a custom field
|
searchable field: Value for a custom field
|
||||||
|
Database: postgresql
|
||||||
|
|||||||
@@ -96,8 +96,13 @@ class AttachmentsControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_save_diff_type
|
def test_save_diff_type
|
||||||
@request.session[:user_id] = 1 # admin
|
user1 = User.find(1)
|
||||||
|
user1.pref[:diff_type] = nil
|
||||||
|
user1.preference.save
|
||||||
user = User.find(1)
|
user = User.find(1)
|
||||||
|
assert_nil user.pref[:diff_type]
|
||||||
|
|
||||||
|
@request.session[:user_id] = 1 # admin
|
||||||
get :show, :id => 5
|
get :show, :id => 5
|
||||||
assert_response :success
|
assert_response :success
|
||||||
assert_template 'diff'
|
assert_template 'diff'
|
||||||
|
|||||||
@@ -2521,6 +2521,18 @@ class IssuesControllerTest < ActionController::TestCase
|
|||||||
assert_equal 'This is the test_new issue', issue.subject
|
assert_equal 'This is the test_new issue', issue.subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_update_edit_form_should_keep_issue_author
|
||||||
|
@request.session[:user_id] = 3
|
||||||
|
xhr :put, :new, :project_id => 1, :id => 1, :issue => {:subject => 'Changed'}
|
||||||
|
assert_response :success
|
||||||
|
assert_equal 'text/javascript', response.content_type
|
||||||
|
|
||||||
|
issue = assigns(:issue)
|
||||||
|
assert_equal User.find(2), issue.author
|
||||||
|
assert_equal 2, issue.author_id
|
||||||
|
assert_not_equal User.current, issue.author
|
||||||
|
end
|
||||||
|
|
||||||
def test_update_edit_form_should_propose_transitions_based_on_initial_status
|
def test_update_edit_form_should_propose_transitions_based_on_initial_status
|
||||||
@request.session[:user_id] = 2
|
@request.session[:user_id] = 2
|
||||||
WorkflowTransition.delete_all
|
WorkflowTransition.delete_all
|
||||||
|
|||||||
@@ -273,4 +273,12 @@ class QueriesControllerTest < ActionController::TestCase
|
|||||||
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil
|
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil
|
||||||
assert_nil Query.find_by_id(1)
|
assert_nil Query.find_by_id(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_backslash_should_be_escaped_in_filters
|
||||||
|
@request.session[:user_id] = 2
|
||||||
|
get :new, :subject => 'foo/bar'
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'new'
|
||||||
|
assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -53,8 +53,6 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
if @char_1.respond_to?(:force_encoding)
|
if @char_1.respond_to?(:force_encoding)
|
||||||
@char_1.force_encoding('UTF-8')
|
@char_1.force_encoding('UTF-8')
|
||||||
end
|
end
|
||||||
|
|
||||||
Setting.default_language = 'en'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_create_and_update
|
def test_create_and_update
|
||||||
@@ -263,6 +261,8 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_diff
|
def test_diff
|
||||||
|
assert_equal true, @repository.is_default
|
||||||
|
assert_nil @repository.identifier
|
||||||
assert_equal 0, @repository.changesets.count
|
assert_equal 0, @repository.changesets.count
|
||||||
@repository.fetch_changesets
|
@repository.fetch_changesets
|
||||||
@project.reload
|
@project.reload
|
||||||
@@ -320,10 +320,12 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
with_settings :diff_max_lines_displayed => 5 do
|
with_settings :diff_max_lines_displayed => 5 do
|
||||||
# Truncated diff of changeset 2f9c0091
|
# Truncated diff of changeset 2f9c0091
|
||||||
with_cache do
|
with_cache do
|
||||||
get :diff, :id => PRJ_ID, :type => 'inline',
|
with_settings :default_language => 'en' do
|
||||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
get :diff, :id => PRJ_ID, :type => 'inline',
|
||||||
assert_response :success
|
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||||
assert @response.body.include?("... This diff was truncated")
|
assert_response :success
|
||||||
|
assert @response.body.include?("... This diff was truncated")
|
||||||
|
end
|
||||||
with_settings :default_language => 'fr' do
|
with_settings :default_language => 'fr' do
|
||||||
get :diff, :id => PRJ_ID, :type => 'inline',
|
get :diff, :id => PRJ_ID, :type => 'inline',
|
||||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||||
@@ -351,9 +353,55 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
diff = assigns(:diff)
|
diff = assigns(:diff)
|
||||||
assert_not_nil diff
|
assert_not_nil diff
|
||||||
assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
|
assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
|
||||||
|
assert_tag :tag => "form",
|
||||||
|
:attributes => {
|
||||||
|
:action => "/projects/subproject1/repository/revisions/" +
|
||||||
|
"61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff"
|
||||||
|
}
|
||||||
|
assert_tag :tag => 'input',
|
||||||
|
:attributes => {
|
||||||
|
:id => "rev_to",
|
||||||
|
:name => "rev_to",
|
||||||
|
:type => "hidden",
|
||||||
|
:value => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||||
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_diff_path_in_subrepo
|
||||||
|
repo = Repository::Git.create(
|
||||||
|
:project => @project,
|
||||||
|
:url => REPOSITORY_PATH,
|
||||||
|
:identifier => 'test-diff-path',
|
||||||
|
:path_encoding => 'ISO-8859-1'
|
||||||
|
);
|
||||||
|
assert repo
|
||||||
|
assert_equal false, repo.is_default
|
||||||
|
assert_equal 'test-diff-path', repo.identifier
|
||||||
|
get :diff,
|
||||||
|
:id => PRJ_ID,
|
||||||
|
:repository_id => 'test-diff-path',
|
||||||
|
:rev => '61b685fbe55ab05b',
|
||||||
|
:rev_to => '2f9c0091c754a91a',
|
||||||
|
:type => 'inline'
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'diff'
|
||||||
|
diff = assigns(:diff)
|
||||||
|
assert_not_nil diff
|
||||||
|
assert_tag :tag => "form",
|
||||||
|
:attributes => {
|
||||||
|
:action => "/projects/subproject1/repository/test-diff-path/" +
|
||||||
|
"revisions/61b685fbe55ab05b/diff"
|
||||||
|
}
|
||||||
|
assert_tag :tag => 'input',
|
||||||
|
:attributes => {
|
||||||
|
:id => "rev_to",
|
||||||
|
:name => "rev_to",
|
||||||
|
:type => "hidden",
|
||||||
|
:value => '2f9c0091c754a91a'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def test_diff_latin_1
|
def test_diff_latin_1
|
||||||
if @ruby19_non_utf8_pass
|
if @ruby19_non_utf8_pass
|
||||||
puts_ruby19_non_utf8_pass()
|
puts_ruby19_non_utf8_pass()
|
||||||
@@ -385,8 +433,13 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_save_diff_type
|
def test_save_diff_type
|
||||||
@request.session[:user_id] = 1 # admin
|
user1 = User.find(1)
|
||||||
|
user1.pref[:diff_type] = nil
|
||||||
|
user1.preference.save
|
||||||
user = User.find(1)
|
user = User.find(1)
|
||||||
|
assert_nil user.pref[:diff_type]
|
||||||
|
|
||||||
|
@request.session[:user_id] = 1 # admin
|
||||||
get :diff,
|
get :diff,
|
||||||
:id => PRJ_ID,
|
:id => PRJ_ID,
|
||||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||||
@@ -479,6 +532,21 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_revisions
|
||||||
|
assert_equal 0, @repository.changesets.count
|
||||||
|
@repository.fetch_changesets
|
||||||
|
@project.reload
|
||||||
|
assert_equal NUM_REV, @repository.changesets.count
|
||||||
|
get :revisions, :id => PRJ_ID
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'revisions'
|
||||||
|
assert_tag :tag => 'form',
|
||||||
|
:attributes => {
|
||||||
|
:method => 'get',
|
||||||
|
:action => '/projects/subproject1/repository/revision'
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
def test_revision
|
def test_revision
|
||||||
assert_equal 0, @repository.changesets.count
|
assert_equal 0, @repository.changesets.count
|
||||||
@repository.fetch_changesets
|
@repository.fetch_changesets
|
||||||
|
|||||||
@@ -110,6 +110,14 @@ class RolesControllerTest < ActionController::TestCase
|
|||||||
assert_response :success
|
assert_response :success
|
||||||
assert_template 'edit'
|
assert_template 'edit'
|
||||||
assert_equal Role.find(1), assigns(:role)
|
assert_equal Role.find(1), assigns(:role)
|
||||||
|
assert_select 'select[name=?]', 'role[issues_visibility]'
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_edit_anonymous
|
||||||
|
get :edit, :id => Role.anonymous.id
|
||||||
|
assert_response :success
|
||||||
|
assert_template 'edit'
|
||||||
|
assert_select 'select[name=?]', 'role[issues_visibility]', 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_edit_invalid_should_respond_with_404
|
def test_edit_invalid_should_respond_with_404
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ class ApiTest::IssuesTest < ActionController::IntegrationTest
|
|||||||
:member_roles,
|
:member_roles,
|
||||||
:issues,
|
:issues,
|
||||||
:issue_statuses,
|
:issue_statuses,
|
||||||
|
:issue_relations,
|
||||||
:versions,
|
:versions,
|
||||||
:trackers,
|
:trackers,
|
||||||
:projects_trackers,
|
:projects_trackers,
|
||||||
|
|||||||
@@ -61,6 +61,8 @@ module ObjectHelpers
|
|||||||
|
|
||||||
def Issue.generate!(attributes={})
|
def Issue.generate!(attributes={})
|
||||||
issue = Issue.new(attributes)
|
issue = Issue.new(attributes)
|
||||||
|
issue.project ||= Project.find(1)
|
||||||
|
issue.tracker ||= issue.project.trackers.first
|
||||||
issue.subject = 'Generated' if issue.subject.blank?
|
issue.subject = 'Generated' if issue.subject.blank?
|
||||||
issue.author ||= User.find(2)
|
issue.author ||= User.find(2)
|
||||||
yield issue if block_given?
|
yield issue if block_given?
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ require File.expand_path('../../test_helper', __FILE__)
|
|||||||
class BoardTest < ActiveSupport::TestCase
|
class BoardTest < ActiveSupport::TestCase
|
||||||
fixtures :projects, :boards, :messages, :attachments, :watchers
|
fixtures :projects, :boards, :messages, :attachments, :watchers
|
||||||
|
|
||||||
|
include Redmine::I18n
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
@project = Project.find(1)
|
@project = Project.find(1)
|
||||||
end
|
end
|
||||||
@@ -41,6 +43,7 @@ class BoardTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_parent_should_be_in_same_project
|
def test_parent_should_be_in_same_project
|
||||||
|
set_language_if_valid 'en'
|
||||||
board = Board.new(:project_id => 3, :name => 'Test', :description => 'Test', :parent_id => 1)
|
board = Board.new(:project_id => 3, :name => 'Test', :description => 'Test', :parent_id => 1)
|
||||||
assert !board.save
|
assert !board.save
|
||||||
assert_include "Parent forum is invalid", board.errors.full_messages
|
assert_include "Parent forum is invalid", board.errors.full_messages
|
||||||
|
|||||||
@@ -179,7 +179,8 @@ class ChangesetTest < ActiveSupport::TestCase
|
|||||||
end
|
end
|
||||||
|
|
||||||
def test_commit_closing_a_subproject_issue
|
def test_commit_closing_a_subproject_issue
|
||||||
with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do
|
with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes',
|
||||||
|
:default_language => 'en' do
|
||||||
issue = Issue.find(5)
|
issue = Issue.find(5)
|
||||||
assert !issue.closed?
|
assert !issue.closed?
|
||||||
assert_difference 'Journal.count' do
|
assert_difference 'Journal.count' do
|
||||||
|
|||||||
@@ -212,4 +212,9 @@ class CustomFieldTest < ActiveSupport::TestCase
|
|||||||
assert_nil CustomField.new(:field_format => 'text').value_class
|
assert_nil CustomField.new(:field_format => 'text').value_class
|
||||||
assert_nil CustomField.new.value_class
|
assert_nil CustomField.new.value_class
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_value_from_keyword_for_list_custom_field
|
||||||
|
field = CustomField.find(1)
|
||||||
|
assert_equal 'PostgreSQL', field.value_from_keyword('postgresql', Issue.find(1))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -253,8 +253,15 @@ RAW
|
|||||||
|
|
||||||
project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
|
project_url = {:controller => 'projects', :action => 'show', :id => 'subproject1'}
|
||||||
|
|
||||||
source_url = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file']}
|
source_url = '/projects/ecookbook/repository/entry/some/file'
|
||||||
source_url_with_ext = {:controller => 'repositories', :action => 'entry', :id => 'ecookbook', :path => ['some', 'file.ext']}
|
source_url_with_rev = '/projects/ecookbook/repository/revisions/52/entry/some/file'
|
||||||
|
source_url_with_ext = '/projects/ecookbook/repository/entry/some/file.ext'
|
||||||
|
source_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/entry/some/file.ext'
|
||||||
|
|
||||||
|
export_url = '/projects/ecookbook/repository/raw/some/file'
|
||||||
|
export_url_with_rev = '/projects/ecookbook/repository/revisions/52/raw/some/file'
|
||||||
|
export_url_with_ext = '/projects/ecookbook/repository/raw/some/file.ext'
|
||||||
|
export_url_with_rev_and_ext = '/projects/ecookbook/repository/revisions/52/raw/some/file.ext'
|
||||||
|
|
||||||
to_test = {
|
to_test = {
|
||||||
# tickets
|
# tickets
|
||||||
@@ -284,12 +291,16 @@ RAW
|
|||||||
'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
|
'source:/some/file. ' => link_to('source:/some/file', source_url, :class => 'source') + ".",
|
||||||
'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
|
'source:/some/file.ext. ' => link_to('source:/some/file.ext', source_url_with_ext, :class => 'source') + ".",
|
||||||
'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
|
'source:/some/file, ' => link_to('source:/some/file', source_url, :class => 'source') + ",",
|
||||||
'source:/some/file@52' => link_to('source:/some/file@52', source_url.merge(:rev => 52), :class => 'source'),
|
'source:/some/file@52' => link_to('source:/some/file@52', source_url_with_rev, :class => 'source'),
|
||||||
'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_ext.merge(:rev => 52), :class => 'source'),
|
'source:/some/file.ext@52' => link_to('source:/some/file.ext@52', source_url_with_rev_and_ext, :class => 'source'),
|
||||||
'source:/some/file#L110' => link_to('source:/some/file#L110', source_url.merge(:anchor => 'L110'), :class => 'source'),
|
'source:/some/file#L110' => link_to('source:/some/file#L110', source_url + "#L110", :class => 'source'),
|
||||||
'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext.merge(:anchor => 'L110'), :class => 'source'),
|
'source:/some/file.ext#L110' => link_to('source:/some/file.ext#L110', source_url_with_ext + "#L110", :class => 'source'),
|
||||||
'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url.merge(:rev => 52, :anchor => 'L110'), :class => 'source'),
|
'source:/some/file@52#L110' => link_to('source:/some/file@52#L110', source_url_with_rev + "#L110", :class => 'source'),
|
||||||
'export:/some/file' => link_to('export:/some/file', source_url.merge(:format => 'raw'), :class => 'source download'),
|
# export
|
||||||
|
'export:/some/file' => link_to('export:/some/file', export_url, :class => 'source download'),
|
||||||
|
'export:/some/file.ext' => link_to('export:/some/file.ext', export_url_with_ext, :class => 'source download'),
|
||||||
|
'export:/some/file@52' => link_to('export:/some/file@52', export_url_with_rev, :class => 'source download'),
|
||||||
|
'export:/some/file.ext@52' => link_to('export:/some/file.ext@52', export_url_with_rev_and_ext, :class => 'source download'),
|
||||||
# forum
|
# forum
|
||||||
'forum#2' => link_to('Discussion', board_url, :class => 'board'),
|
'forum#2' => link_to('Discussion', board_url, :class => 'board'),
|
||||||
'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
|
'forum:Discussion' => link_to('Discussion', board_url, :class => 'board'),
|
||||||
|
|||||||
@@ -109,51 +109,55 @@ class IssuesHelperTest < ActionView::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_a_start_date_attribute_should_format_the_current_date
|
context "with a start_date attribute" do
|
||||||
@detail = JournalDetail.new(
|
should "format the current date" do
|
||||||
|
@detail = JournalDetail.new(
|
||||||
:property => 'attr',
|
:property => 'attr',
|
||||||
:old_value => '2010-01-01',
|
:old_value => '2010-01-01',
|
||||||
:value => '2010-01-31',
|
:value => '2010-01-31',
|
||||||
:prop_key => 'start_date'
|
:prop_key => 'start_date'
|
||||||
)
|
)
|
||||||
with_settings :date_format => '%m/%d/%Y' do
|
with_settings :date_format => '%m/%d/%Y' do
|
||||||
assert_match "01/31/2010", show_detail(@detail, true)
|
assert_match "01/31/2010", show_detail(@detail, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def test_with_a_start_date_attribute_should_format_the_old_date
|
should "format the old date" do
|
||||||
@detail = JournalDetail.new(
|
@detail = JournalDetail.new(
|
||||||
:property => 'attr',
|
:property => 'attr',
|
||||||
:old_value => '2010-01-01',
|
:old_value => '2010-01-01',
|
||||||
:value => '2010-01-31',
|
:value => '2010-01-31',
|
||||||
:prop_key => 'start_date'
|
:prop_key => 'start_date'
|
||||||
)
|
)
|
||||||
with_settings :date_format => '%m/%d/%Y' do
|
with_settings :date_format => '%m/%d/%Y' do
|
||||||
assert_match "01/01/2010", show_detail(@detail, true)
|
assert_match "01/01/2010", show_detail(@detail, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_with_a_due_date_attribute_should_with_a_due_date_attribute
|
context "with a due_date attribute" do
|
||||||
@detail = JournalDetail.new(
|
should "format the current date" do
|
||||||
|
@detail = JournalDetail.new(
|
||||||
:property => 'attr',
|
:property => 'attr',
|
||||||
:old_value => '2010-01-01',
|
:old_value => '2010-01-01',
|
||||||
:value => '2010-01-31',
|
:value => '2010-01-31',
|
||||||
:prop_key => 'due_date'
|
:prop_key => 'due_date'
|
||||||
)
|
)
|
||||||
with_settings :date_format => '%m/%d/%Y' do
|
with_settings :date_format => '%m/%d/%Y' do
|
||||||
assert_match "01/31/2010", show_detail(@detail, true)
|
assert_match "01/31/2010", show_detail(@detail, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
def test_with_a_due_date_attribute_should_format_the_old_date
|
should "format the old date" do
|
||||||
@detail = JournalDetail.new(
|
@detail = JournalDetail.new(
|
||||||
:property => 'attr',
|
:property => 'attr',
|
||||||
:old_value => '2010-01-01',
|
:old_value => '2010-01-01',
|
||||||
:value => '2010-01-31',
|
:value => '2010-01-31',
|
||||||
:prop_key => 'due_date'
|
:prop_key => 'due_date'
|
||||||
)
|
)
|
||||||
with_settings :date_format => '%m/%d/%Y' do
|
with_settings :date_format => '%m/%d/%Y' do
|
||||||
assert_match "01/01/2010", show_detail(@detail, true)
|
assert_match "01/01/2010", show_detail(@detail, true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,17 @@
|
|||||||
require File.expand_path('../../test_helper', __FILE__)
|
require File.expand_path('../../test_helper', __FILE__)
|
||||||
|
|
||||||
class IssueRelationTest < ActiveSupport::TestCase
|
class IssueRelationTest < ActiveSupport::TestCase
|
||||||
fixtures :issue_relations, :issues
|
fixtures :projects,
|
||||||
|
:users,
|
||||||
|
:roles,
|
||||||
|
:members,
|
||||||
|
:member_roles,
|
||||||
|
:issues,
|
||||||
|
:issue_statuses,
|
||||||
|
:issue_relations,
|
||||||
|
:enabled_modules,
|
||||||
|
:enumerations,
|
||||||
|
:trackers
|
||||||
|
|
||||||
def test_create
|
def test_create
|
||||||
from = Issue.find(1)
|
from = Issue.find(1)
|
||||||
|
|||||||
+29
-13
@@ -25,7 +25,7 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
:versions,
|
:versions,
|
||||||
:issue_statuses, :issue_categories, :issue_relations, :workflows,
|
:issue_statuses, :issue_categories, :issue_relations, :workflows,
|
||||||
:enumerations,
|
:enumerations,
|
||||||
:issues,
|
:issues, :journals, :journal_details,
|
||||||
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
|
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
|
||||||
:time_entries
|
:time_entries
|
||||||
|
|
||||||
@@ -105,18 +105,6 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
assert_visibility_match User.anonymous, issues
|
assert_visibility_match User.anonymous, issues
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_visible_scope_for_anonymous_with_own_issues_visibility
|
|
||||||
Role.anonymous.update_attribute :issues_visibility, 'own'
|
|
||||||
Issue.create!(:project_id => 1, :tracker_id => 1,
|
|
||||||
:author_id => User.anonymous.id,
|
|
||||||
:subject => 'Issue by anonymous')
|
|
||||||
|
|
||||||
issues = Issue.visible(User.anonymous).all
|
|
||||||
assert issues.any?
|
|
||||||
assert_nil issues.detect {|issue| issue.author != User.anonymous}
|
|
||||||
assert_visibility_match User.anonymous, issues
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_visible_scope_for_anonymous_without_view_issues_permissions
|
def test_visible_scope_for_anonymous_without_view_issues_permissions
|
||||||
# Anonymous user should not see issues without permission
|
# Anonymous user should not see issues without permission
|
||||||
Role.anonymous.remove_permission!(:view_issues)
|
Role.anonymous.remove_permission!(:view_issues)
|
||||||
@@ -125,6 +113,20 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
assert_visibility_match User.anonymous, issues
|
assert_visibility_match User.anonymous, issues
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
|
||||||
|
assert Role.anonymous.update_attribute(:issues_visibility, 'default')
|
||||||
|
issue = Issue.generate_for_project!(Project.find(1), :author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
|
||||||
|
assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
|
||||||
|
assert !issue.visible?(User.anonymous)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
|
||||||
|
assert Role.anonymous.update_attribute(:issues_visibility, 'own')
|
||||||
|
issue = Issue.generate_for_project!(Project.find(1), :author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
|
||||||
|
assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
|
||||||
|
assert !issue.visible?(User.anonymous)
|
||||||
|
end
|
||||||
|
|
||||||
def test_visible_scope_for_non_member
|
def test_visible_scope_for_non_member
|
||||||
user = User.find(9)
|
user = User.find(9)
|
||||||
assert user.projects.empty?
|
assert user.projects.empty?
|
||||||
@@ -1574,4 +1576,18 @@ class IssueTest < ActiveSupport::TestCase
|
|||||||
def test_journals_after_with_blank_arg_should_return_all_journals
|
def test_journals_after_with_blank_arg_should_return_all_journals
|
||||||
assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
|
assert_equal [Journal.find(1), Journal.find(2)], Issue.find(1).journals_after('')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_save_attachments_with_hash_should_save_attachments_in_keys_order
|
||||||
|
set_tmp_attachments_directory
|
||||||
|
issue = Issue.generate!
|
||||||
|
issue.save_attachments({
|
||||||
|
'p0' => {'file' => mock_file_with_options(:original_filename => 'upload')},
|
||||||
|
'3' => {'file' => mock_file_with_options(:original_filename => 'bar')},
|
||||||
|
'1' => {'file' => mock_file_with_options(:original_filename => 'foo')}
|
||||||
|
})
|
||||||
|
issue.attach_saved_attachments
|
||||||
|
|
||||||
|
assert_equal 3, issue.reload.attachments.count
|
||||||
|
assert_equal %w(upload foo bar), issue.attachments.map(&:filename)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -171,6 +171,24 @@ class Redmine::I18nTest < ActiveSupport::TestCase
|
|||||||
assert_equal 'j', day_letter(4)
|
assert_equal 'j', day_letter(4)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_number_to_currency_for_each_language
|
||||||
|
valid_languages.each do |lang|
|
||||||
|
set_language_if_valid lang
|
||||||
|
assert_nothing_raised "#{lang} failure" do
|
||||||
|
number_to_currency(-1000.2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_number_to_currency_default
|
||||||
|
set_language_if_valid 'bs'
|
||||||
|
assert_equal "KM -1000,20", number_to_currency(-1000.2)
|
||||||
|
set_language_if_valid 'de'
|
||||||
|
euro_sign = "\xe2\x82\xac"
|
||||||
|
euro_sign.force_encoding('UTF-8') if euro_sign.respond_to?(:force_encoding)
|
||||||
|
assert_equal "-1000,20 #{euro_sign}", number_to_currency(-1000.2)
|
||||||
|
end
|
||||||
|
|
||||||
def test_valid_languages
|
def test_valid_languages
|
||||||
assert valid_languages.is_a?(Array)
|
assert valid_languages.is_a?(Array)
|
||||||
assert valid_languages.first.is_a?(Symbol)
|
assert valid_languages.first.is_a?(Symbol)
|
||||||
|
|||||||
@@ -100,6 +100,25 @@ class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase
|
|||||||
assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(text, :object => Issue.find(1))
|
assert_equal '<p>Hello world! Object: Issue, Called with no argument and no block of text.</p>', textilizable(text, :object => Issue.find(1))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_extract_macro_options_should_with_args
|
||||||
|
options = extract_macro_options(["arg1", "arg2"], :foo, :size)
|
||||||
|
assert_equal([["arg1", "arg2"], {}], options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_extract_macro_options_should_with_options
|
||||||
|
options = extract_macro_options(["foo=bar", "size=2"], :foo, :size)
|
||||||
|
assert_equal([[], {:foo => "bar", :size => "2"}], options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_extract_macro_options_should_with_args_and_options
|
||||||
|
options = extract_macro_options(["arg1", "arg2", "foo=bar", "size=2"], :foo, :size)
|
||||||
|
assert_equal([["arg1", "arg2"], {:foo => "bar", :size => "2"}], options)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_extract_macro_options_should_parse_options_lazily
|
||||||
|
options = extract_macro_options(["params=x=1&y=2"], :params)
|
||||||
|
assert_equal([[], {:params => "x=1&y=2"}], options)
|
||||||
|
end
|
||||||
|
|
||||||
def test_macro_exception_should_be_displayed
|
def test_macro_exception_should_be_displayed
|
||||||
Redmine::WikiFormatting::Macros.macro :exception do |obj, args|
|
Redmine::WikiFormatting::Macros.macro :exception do |obj, args|
|
||||||
|
|||||||
@@ -177,8 +177,8 @@ class MailHandlerTest < ActiveSupport::TestCase
|
|||||||
assert !issue.new_record?
|
assert !issue.new_record?
|
||||||
issue.reload
|
issue.reload
|
||||||
assert_equal 'New ticket with custom field values', issue.subject
|
assert_equal 'New ticket with custom field values', issue.subject
|
||||||
assert_equal 'Value for a custom field',
|
assert_equal 'PostgreSQL', issue.custom_field_value(1)
|
||||||
issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
|
assert_equal 'Value for a custom field', issue.custom_field_value(2)
|
||||||
assert !issue.description.match(/^searchable field:/i)
|
assert !issue.description.match(/^searchable field:/i)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -373,6 +373,80 @@ class MailHandlerTest < ActiveSupport::TestCase
|
|||||||
assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
|
assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_thunderbird_with_attachment_ja
|
||||||
|
issue = submit_email(
|
||||||
|
'thunderbird_with_attachment_ja.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
assert_equal 1, issue.attachments.size
|
||||||
|
ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
|
||||||
|
ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
|
||||||
|
attachment = issue.attachments.first
|
||||||
|
assert_equal ja, attachment.filename
|
||||||
|
assert_equal 5, attachment.filesize
|
||||||
|
assert File.exist?(attachment.diskfile)
|
||||||
|
assert_equal 5, File.size(attachment.diskfile)
|
||||||
|
assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_gmail_with_attachment_ja
|
||||||
|
issue = submit_email(
|
||||||
|
'gmail_with_attachment_ja.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
assert_equal 1, issue.attachments.size
|
||||||
|
ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
|
||||||
|
ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
|
||||||
|
attachment = issue.attachments.first
|
||||||
|
assert_equal ja, attachment.filename
|
||||||
|
assert_equal 5, attachment.filesize
|
||||||
|
assert File.exist?(attachment.diskfile)
|
||||||
|
assert_equal 5, File.size(attachment.diskfile)
|
||||||
|
assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_thunderbird_with_attachment_latin1
|
||||||
|
issue = submit_email(
|
||||||
|
'thunderbird_with_attachment_iso-8859-1.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
assert_equal 1, issue.attachments.size
|
||||||
|
u = ""
|
||||||
|
u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
|
||||||
|
u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
|
||||||
|
u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
|
||||||
|
11.times { u << u1 }
|
||||||
|
attachment = issue.attachments.first
|
||||||
|
assert_equal "#{u}.png", attachment.filename
|
||||||
|
assert_equal 130, attachment.filesize
|
||||||
|
assert File.exist?(attachment.diskfile)
|
||||||
|
assert_equal 130, File.size(attachment.diskfile)
|
||||||
|
assert_equal '4d80e667ac37dddfe05502530f152abb', attachment.digest
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_gmail_with_attachment_latin1
|
||||||
|
issue = submit_email(
|
||||||
|
'gmail_with_attachment_iso-8859-1.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
assert_equal 1, issue.attachments.size
|
||||||
|
u = ""
|
||||||
|
u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
|
||||||
|
u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
|
||||||
|
u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
|
||||||
|
11.times { u << u1 }
|
||||||
|
attachment = issue.attachments.first
|
||||||
|
assert_equal "#{u}.txt", attachment.filename
|
||||||
|
assert_equal 5, attachment.filesize
|
||||||
|
assert File.exist?(attachment.diskfile)
|
||||||
|
assert_equal 5, File.size(attachment.diskfile)
|
||||||
|
assert_equal 'd8e8fca2dc0f896fd7cb4cb0031ba249', attachment.digest
|
||||||
|
end
|
||||||
|
|
||||||
def test_add_issue_with_iso_8859_1_subject
|
def test_add_issue_with_iso_8859_1_subject
|
||||||
issue = submit_email(
|
issue = submit_email(
|
||||||
'subject_as_iso-8859-1.eml',
|
'subject_as_iso-8859-1.eml',
|
||||||
@@ -382,6 +456,37 @@ class MailHandlerTest < ActiveSupport::TestCase
|
|||||||
assert_equal 'Testmail from Webmail: ä ö ü...', issue.subject
|
assert_equal 'Testmail from Webmail: ä ö ü...', issue.subject
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_add_issue_with_japanese_subject
|
||||||
|
issue = submit_email(
|
||||||
|
'subject_japanese_1.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
|
||||||
|
ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
|
||||||
|
assert_equal ja, issue.subject
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_issue_with_no_subject_header
|
||||||
|
issue = submit_email(
|
||||||
|
'no_subject_header.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
assert_equal '(no subject)', issue.subject
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_issue_with_mixed_japanese_subject
|
||||||
|
issue = submit_email(
|
||||||
|
'subject_japanese_2.eml',
|
||||||
|
:issue => {:project => 'ecookbook'}
|
||||||
|
)
|
||||||
|
assert_kind_of Issue, issue
|
||||||
|
ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
|
||||||
|
ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
|
||||||
|
assert_equal ja, issue.subject
|
||||||
|
end
|
||||||
|
|
||||||
def test_should_ignore_emails_from_locked_users
|
def test_should_ignore_emails_from_locked_users
|
||||||
User.find(2).lock!
|
User.find(2).lock!
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
# encoding: utf-8
|
||||||
|
#
|
||||||
# Redmine - project management software
|
# Redmine - project management software
|
||||||
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
# Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
@@ -106,4 +108,11 @@ class PrincipalTest < ActiveSupport::TestCase
|
|||||||
assert_equal @palmer, results.first
|
assert_equal @palmer, results.first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_like_scope_with_cyrillic_name
|
||||||
|
user = User.generate!(:firstname => 'Соболев', :lastname => 'Денис')
|
||||||
|
results = Principal.like('Собо')
|
||||||
|
assert_equal 1, results.count
|
||||||
|
assert_equal user, results.first
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,17 +28,17 @@ class ProjectNestedSetTest < ActiveSupport::TestCase
|
|||||||
@a2 = Project.create!(:name => 'A2', :identifier => 'projecta2')
|
@a2 = Project.create!(:name => 'A2', :identifier => 'projecta2')
|
||||||
@a2.set_parent!(@a)
|
@a2.set_parent!(@a)
|
||||||
|
|
||||||
|
@c = Project.create!(:name => 'C', :identifier => 'projectc')
|
||||||
|
@c1 = Project.create!(:name => 'C1', :identifier => 'projectc1')
|
||||||
|
@c1.set_parent!(@c)
|
||||||
|
|
||||||
@b = Project.create!(:name => 'B', :identifier => 'projectb')
|
@b = Project.create!(:name => 'B', :identifier => 'projectb')
|
||||||
|
@b2 = Project.create!(:name => 'B2', :identifier => 'projectb2')
|
||||||
|
@b2.set_parent!(@b)
|
||||||
@b1 = Project.create!(:name => 'B1', :identifier => 'projectb1')
|
@b1 = Project.create!(:name => 'B1', :identifier => 'projectb1')
|
||||||
@b1.set_parent!(@b)
|
@b1.set_parent!(@b)
|
||||||
@b11 = Project.create!(:name => 'B11', :identifier => 'projectb11')
|
@b11 = Project.create!(:name => 'B11', :identifier => 'projectb11')
|
||||||
@b11.set_parent!(@b1)
|
@b11.set_parent!(@b1)
|
||||||
@b2 = Project.create!(:name => 'B2', :identifier => 'projectb2')
|
|
||||||
@b2.set_parent!(@b)
|
|
||||||
|
|
||||||
@c = Project.create!(:name => 'C', :identifier => 'projectc')
|
|
||||||
@c1 = Project.create!(:name => 'C1', :identifier => 'projectc1')
|
|
||||||
@c1.set_parent!(@c)
|
|
||||||
|
|
||||||
@a, @a1, @a2, @b, @b1, @b11, @b2, @c, @c1 = *(Project.all.sort_by(&:name))
|
@a, @a1, @a2, @b, @b1, @b11, @b2, @c, @c1 = *(Project.all.sort_by(&:name))
|
||||||
end
|
end
|
||||||
@@ -47,6 +47,13 @@ class ProjectNestedSetTest < ActiveSupport::TestCase
|
|||||||
assert_valid_nested_set
|
assert_valid_nested_set
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_rebuild_should_build_valid_tree
|
||||||
|
Project.update_all "lft = NULL, rgt = NULL"
|
||||||
|
|
||||||
|
Project.rebuild!
|
||||||
|
assert_valid_nested_set
|
||||||
|
end
|
||||||
|
|
||||||
def test_moving_a_child_to_a_different_parent_should_keep_valid_tree
|
def test_moving_a_child_to_a_different_parent_should_keep_valid_tree
|
||||||
assert_no_difference 'Project.count' do
|
assert_no_difference 'Project.count' do
|
||||||
Project.find_by_name('B1').set_parent!(Project.find_by_name('A2'))
|
Project.find_by_name('B1').set_parent!(Project.find_by_name('A2'))
|
||||||
|
|||||||
@@ -217,6 +217,40 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
|||||||
assert_equal h1, h2
|
assert_equal h1, h2
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_keep_extra_report_last_commit_in_clear_changesets
|
||||||
|
assert_nil @repository.extra_info
|
||||||
|
h = {}
|
||||||
|
h["extra_report_last_commit"] = "1"
|
||||||
|
@repository.merge_extra_info(h)
|
||||||
|
@repository.save
|
||||||
|
@project.reload
|
||||||
|
|
||||||
|
assert_equal 0, @repository.changesets.count
|
||||||
|
@repository.fetch_changesets
|
||||||
|
@project.reload
|
||||||
|
|
||||||
|
assert_equal NUM_REV, @repository.changesets.count
|
||||||
|
@repository.send(:clear_changesets)
|
||||||
|
assert_equal 1, @repository.extra_info.size
|
||||||
|
assert_equal "1", @repository.extra_info["extra_report_last_commit"]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_refetch_after_clear_changesets
|
||||||
|
assert_nil @repository.extra_info
|
||||||
|
assert_equal 0, @repository.changesets.count
|
||||||
|
@repository.fetch_changesets
|
||||||
|
@project.reload
|
||||||
|
assert_equal NUM_REV, @repository.changesets.count
|
||||||
|
|
||||||
|
@repository.send(:clear_changesets)
|
||||||
|
@project.reload
|
||||||
|
assert_equal 0, @repository.changesets.count
|
||||||
|
|
||||||
|
@repository.fetch_changesets
|
||||||
|
@project.reload
|
||||||
|
assert_equal NUM_REV, @repository.changesets.count
|
||||||
|
end
|
||||||
|
|
||||||
def test_parents
|
def test_parents
|
||||||
assert_equal 0, @repository.changesets.count
|
assert_equal 0, @repository.changesets.count
|
||||||
@repository.fetch_changesets
|
@repository.fetch_changesets
|
||||||
|
|||||||
@@ -54,4 +54,19 @@ class UserPreferenceTest < ActiveSupport::TestCase
|
|||||||
assert up.save
|
assert up.save
|
||||||
assert_kind_of Hash, up.others
|
assert_kind_of Hash, up.others
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_reading_value_from_nil_others_hash
|
||||||
|
up = UserPreference.new(:user => User.new)
|
||||||
|
up.others = nil
|
||||||
|
assert_nil up.others
|
||||||
|
assert_nil up[:foo]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_writing_value_to_nil_others_hash
|
||||||
|
up = UserPreference.new(:user => User.new)
|
||||||
|
up.others = nil
|
||||||
|
assert_nil up.others
|
||||||
|
up[:foo] = 'bar'
|
||||||
|
assert_equal 'bar', up[:foo]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -32,7 +32,13 @@ class VersionTest < ActiveSupport::TestCase
|
|||||||
|
|
||||||
def test_invalid_effective_date_validation
|
def test_invalid_effective_date_validation
|
||||||
v = Version.new(:project => Project.find(1), :name => '1.1', :effective_date => '99999-01-01')
|
v = Version.new(:project => Project.find(1), :name => '1.1', :effective_date => '99999-01-01')
|
||||||
assert !v.save
|
assert !v.valid?
|
||||||
|
v.effective_date = '2012-11-33'
|
||||||
|
assert !v.valid?
|
||||||
|
v.effective_date = '2012-31-11'
|
||||||
|
assert !v.valid?
|
||||||
|
v.effective_date = 'ABC'
|
||||||
|
assert !v.valid?
|
||||||
assert_include I18n.translate('activerecord.errors.messages.not_a_date'),
|
assert_include I18n.translate('activerecord.errors.messages.not_a_date'),
|
||||||
v.errors[:effective_date]
|
v.errors[:effective_date]
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user