##// END OF EJS Templates
Merged rails-4.1 branch (#14534)....
Jean-Philippe Lang -
r13100:2d1866d966d9
parent child
Show More
@@ -0,0 +1,3
1 #! /bin/sh
2
3 JRUBY_OPTS=-J-Xmx1024m bundle exec rake test:${TEST_SUITE}
@@ -0,0 +1,6
1 #!/usr/bin/env ruby
2
3 ENV["RAILS_ENV"] ||= "production"
4 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
5 puts
6 puts Redmine::Info.environment
@@ -0,0 +1,3
1 #!/usr/bin/env ruby.exe
2 ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
3 load Gem.bin_path('bundler', 'bundle')
@@ -0,0 +1,4
1 #!/usr/bin/env ruby.exe
2 APP_PATH = File.expand_path('../../config/application', __FILE__)
3 require_relative '../config/boot'
4 require 'rails/commands'
@@ -0,0 +1,4
1 #!/usr/bin/env ruby.exe
2 require_relative '../config/boot'
3 require 'rake'
4 Rake.application.run
@@ -3,8 +3,6
3 # You can also run tests on your environment.
3 # You can also run tests on your environment.
4 language: ruby
4 language: ruby
5 rvm:
5 rvm:
6 - 1.8.7
7 - 1.9.2
8 - 1.9.3
6 - 1.9.3
9 - 2.0
7 - 2.0
10 - 2.1
8 - 2.1
@@ -34,6 +32,7 script:
34 - "bundle install"
32 - "bundle install"
35 - "RUN_ON_NOT_OFFICIAL='' RUBY_VER=1.9 BRANCH=trunk bundle exec rake config/database.yml"
33 - "RUN_ON_NOT_OFFICIAL='' RUBY_VER=1.9 BRANCH=trunk bundle exec rake config/database.yml"
36 - "bundle install"
34 - "bundle install"
37 - "JRUBY_OPTS=-J-Xmx1024m bundle exec rake ci"
35 - "bundle exec rake ci:setup"
36 - "sh .travis.run-test.sh"
38 notifications:
37 notifications:
39 email: false
38 email: false
@@ -1,12 +1,17
1 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 gem "rails", "3.2.19"
3 gem "rails", "4.1.6"
4 gem "jquery-rails", "~> 3.1.1"
4 gem "jquery-rails", "~> 3.1.1"
5 gem "coderay", "~> 1.1.0"
5 gem "coderay", "~> 1.1.0"
6 gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
7 gem "builder", ">= 3.0.4"
6 gem "builder", ">= 3.0.4"
8 gem "request_store", "1.0.5"
7 gem "request_store", "1.0.5"
9 gem "mime-types"
8 gem "mime-types"
9 gem "awesome_nested_set", "3.0.0"
10 gem "protected_attributes"
11 gem "actionpack-action_caching"
12
13 # Windows does not include zoneinfo files, so bundle the tzinfo-data gem
14 gem 'tzinfo-data', platforms: [:mingw, :mswin, :jruby]
10 gem "rbpdf", "~> 1.18.1"
15 gem "rbpdf", "~> 1.18.1"
11
16
12 # Optional gem for LDAP authentication
17 # Optional gem for LDAP authentication
@@ -23,16 +28,12 end
23 platforms :mri, :mingw do
28 platforms :mri, :mingw do
24 # Optional gem for exporting the gantt to a PNG file, not supported with jruby
29 # Optional gem for exporting the gantt to a PNG file, not supported with jruby
25 group :rmagick do
30 group :rmagick do
26 # RMagick 2 supports ruby 1.9
27 # RMagick 1 would be fine for ruby 1.8 but Bundler does not support
28 # different requirements for the same gem on different platforms
29 gem "rmagick", ">= 2.0.0"
31 gem "rmagick", ">= 2.0.0"
30 end
32 end
31
33
32 # Optional Markdown support, not for JRuby
34 # Optional Markdown support, not for JRuby
33 group :markdown do
35 group :markdown do
34 # TODO: upgrade to redcarpet 3.x when ruby1.8 support is dropped
36 gem "redcarpet", "~> 3.1.2"
35 gem "redcarpet", "~> 2.3.0"
36 end
37 end
37 end
38 end
38
39
@@ -57,7 +58,6 if File.exist?(database_file)
57 gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw]
58 gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw]
58 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
59 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
59 when 'mysql'
60 when 'mysql'
60 gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw]
61 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
61 gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
62 when /postgresql/
62 when /postgresql/
63 gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw]
63 gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw]
@@ -85,24 +85,20 group :development do
85 end
85 end
86
86
87 group :test do
87 group :test do
88 gem "shoulda", "~> 3.3.2"
88 gem "minitest"
89 gem "shoulda-matchers", "1.4.1"
89 gem "shoulda-context"
90 gem "mocha", "~> 1.0.0", :require => 'mocha/api'
90 gem "mocha", "~> 1.0.0", :require => 'mocha/api'
91 if RUBY_VERSION >= '1.9.3'
91 # For running UI tests
92 gem "capybara", "~> 2.1.0"
92 gem "capybara", "~> 2.1.0"
93 gem "selenium-webdriver"
93 gem "selenium-webdriver"
94 end
94 end
95 end
96
95
97 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
96 local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
98 if File.exists?(local_gemfile)
97 if File.exists?(local_gemfile)
99 puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v`
98 eval_gemfile local_gemfile
100 instance_eval File.read(local_gemfile)
101 end
99 end
102
100
103 # Load plugins' Gemfiles
101 # Load plugins' Gemfiles
104 Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file|
102 Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file|
105 puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
103 eval_gemfile file
106 #TODO: switch to "eval_gemfile file" when bundler >= 1.2.0 will be required (rails 4)
107 instance_eval File.read(file), file
108 end
104 end
@@ -34,7 +34,7 class AdminController < ApplicationController
34
34
35 scope = Project.status(@status).order('lft')
35 scope = Project.status(@status).order('lft')
36 scope = scope.like(params[:name]) if params[:name].present?
36 scope = scope.like(params[:name]) if params[:name].present?
37 @projects = scope.all
37 @projects = scope.to_a
38
38
39 render :action => "projects", :layout => false if request.xhr?
39 render :action => "projects", :layout => false if request.xhr?
40 end
40 end
@@ -496,7 +496,7 class ApplicationController < ActionController::Base
496 end
496 end
497
497
498 def render_feed(items, options={})
498 def render_feed(items, options={})
499 @items = items || []
499 @items = (items || []).to_a
500 @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
500 @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
501 @items = @items.slice(0, Setting.feeds_limit.to_i)
501 @items = @items.slice(0, Setting.feeds_limit.to_i)
502 @title = options[:title] || Setting.app_title
502 @title = options[:title] || Setting.app_title
@@ -26,7 +26,7 class AutoCompletesController < ApplicationController
26 if q.match(/\A#?(\d+)\z/)
26 if q.match(/\A#?(\d+)\z/)
27 @issues << scope.find_by_id($1.to_i)
27 @issues << scope.find_by_id($1.to_i)
28 end
28 end
29 @issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all
29 @issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).to_a
30 @issues.compact!
30 @issues.compact!
31 end
31 end
32 render :layout => false
32 render :layout => false
@@ -25,7 +25,7 class BoardsController < ApplicationController
25 helper :watchers
25 helper :watchers
26
26
27 def index
27 def index
28 @boards = @project.boards.includes(:project, :last_message => :author).all
28 @boards = @project.boards.preload(:project, :last_message => :author).to_a
29 # show the board if there is only one
29 # show the board if there is only one
30 if @boards.size == 1
30 if @boards.size == 1
31 @board = @boards.first
31 @board = @boards.first
@@ -45,12 +45,13 class BoardsController < ApplicationController
45 @topic_pages = Paginator.new @topic_count, per_page_option, params['page']
45 @topic_pages = Paginator.new @topic_count, per_page_option, params['page']
46 @topics = @board.topics.
46 @topics = @board.topics.
47 reorder("#{Message.table_name}.sticky DESC").
47 reorder("#{Message.table_name}.sticky DESC").
48 includes(:last_reply).
48 joins("LEFT OUTER JOIN #{Message.table_name} last_replies_messages ON last_replies_messages.id = #{Message.table_name}.last_reply_id").
49 references(:last_reply).
49 limit(@topic_pages.per_page).
50 limit(@topic_pages.per_page).
50 offset(@topic_pages.offset).
51 offset(@topic_pages.offset).
51 order(sort_clause).
52 order(sort_clause).
52 preload(:author, {:last_reply => :author}).
53 preload(:author, {:last_reply => :author}).
53 all
54 to_a
54 @message = Message.new(:board => @board)
55 @message = Message.new(:board => @board)
55 render :action => 'show', :layout => !request.xhr?
56 render :action => 'show', :layout => !request.xhr?
56 }
57 }
@@ -59,7 +60,7 class BoardsController < ApplicationController
59 reorder('created_on DESC').
60 reorder('created_on DESC').
60 includes(:author, :board).
61 includes(:author, :board).
61 limit(Setting.feeds_limit.to_i).
62 limit(Setting.feeds_limit.to_i).
62 all
63 to_a
63 render_feed(@messages, :title => "#{@project}: #{@board}")
64 render_feed(@messages, :title => "#{@project}: #{@board}")
64 }
65 }
65 end
66 end
@@ -27,7 +27,7 class DocumentsController < ApplicationController
27
27
28 def index
28 def index
29 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
29 @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
30 documents = @project.documents.includes(:attachments, :category).all
30 documents = @project.documents.includes(:attachments, :category).to_a
31 case @sort_by
31 case @sort_by
32 when 'date'
32 when 'date'
33 @grouped = documents.group_by {|d| d.updated_on.to_date }
33 @grouped = documents.group_by {|d| d.updated_on.to_date }
@@ -43,7 +43,7 class DocumentsController < ApplicationController
43 end
43 end
44
44
45 def show
45 def show
46 @attachments = @document.attachments.all
46 @attachments = @document.attachments.to_a
47 end
47 end
48
48
49 def new
49 def new
@@ -69,7 +69,7 class DocumentsController < ApplicationController
69
69
70 def update
70 def update
71 @document.safe_attributes = params[:document]
71 @document.safe_attributes = params[:document]
72 if request.put? and @document.save
72 if @document.save
73 flash[:notice] = l(:notice_successful_update)
73 flash[:notice] = l(:notice_successful_update)
74 redirect_to document_path(@document)
74 redirect_to document_path(@document)
75 else
75 else
@@ -32,7 +32,7 class EnumerationsController < ApplicationController
32 format.api {
32 format.api {
33 @klass = Enumeration.get_subclass(params[:type])
33 @klass = Enumeration.get_subclass(params[:type])
34 if @klass
34 if @klass
35 @enumerations = @klass.shared.sorted.all
35 @enumerations = @klass.shared.sorted.to_a
36 else
36 else
37 render_404
37 render_404
38 end
38 end
@@ -56,7 +56,7 class EnumerationsController < ApplicationController
56 end
56 end
57
57
58 def update
58 def update
59 if request.put? && @enumeration.update_attributes(params[:enumeration])
59 if @enumeration.update_attributes(params[:enumeration])
60 flash[:notice] = l(:notice_successful_update)
60 flash[:notice] = l(:notice_successful_update)
61 redirect_to enumerations_path
61 redirect_to enumerations_path
62 else
62 else
@@ -75,7 +75,7 class EnumerationsController < ApplicationController
75 redirect_to enumerations_path
75 redirect_to enumerations_path
76 return
76 return
77 end
77 end
78 @enumerations = @enumeration.class.system.all - [@enumeration]
78 @enumerations = @enumeration.class.system.to_a - [@enumeration]
79 end
79 end
80
80
81 private
81 private
@@ -31,8 +31,10 class FilesController < ApplicationController
31 'size' => "#{Attachment.table_name}.filesize",
31 'size' => "#{Attachment.table_name}.filesize",
32 'downloads' => "#{Attachment.table_name}.downloads"
32 'downloads' => "#{Attachment.table_name}.downloads"
33
33
34 @containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)]
34 @containers = [Project.includes(:attachments).
35 @containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse
35 references(:attachments).reorder(sort_clause).find(@project.id)]
36 @containers += @project.versions.includes(:attachments).
37 references(:attachments).reorder(sort_clause).to_a.sort.reverse
36 render :layout => !request.xhr?
38 render :layout => !request.xhr?
37 end
39 end
38
40
@@ -27,13 +27,13 class GroupsController < ApplicationController
27 def index
27 def index
28 respond_to do |format|
28 respond_to do |format|
29 format.html {
29 format.html {
30 @groups = Group.sorted.all
30 @groups = Group.sorted.to_a
31 @user_count_by_group_id = user_count_by_group_id
31 @user_count_by_group_id = user_count_by_group_id
32 }
32 }
33 format.api {
33 format.api {
34 scope = Group.sorted
34 scope = Group.sorted
35 scope = scope.givable unless params[:builtin] == '1'
35 scope = scope.givable unless params[:builtin] == '1'
36 @groups = scope.all
36 @groups = scope.to_a
37 }
37 }
38 end
38 end
39 end
39 end
@@ -95,7 +95,7 class GroupsController < ApplicationController
95 end
95 end
96
96
97 def add_users
97 def add_users
98 @users = User.where(:id => (params[:user_id] || params[:user_ids])).all
98 @users = User.where(:id => (params[:user_id] || params[:user_ids])).to_a
99 @group.users << @users if request.post?
99 @group.users << @users if request.post?
100 respond_to do |format|
100 respond_to do |format|
101 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
101 format.html { redirect_to edit_group_path(@group, :tab => 'users') }
@@ -27,7 +27,7 class IssueCategoriesController < ApplicationController
27 def index
27 def index
28 respond_to do |format|
28 respond_to do |format|
29 format.html { redirect_to_settings_in_projects }
29 format.html { redirect_to_settings_in_projects }
30 format.api { @categories = @project.issue_categories.all }
30 format.api { @categories = @project.issue_categories.to_a }
31 end
31 end
32 end
32 end
33
33
@@ -29,7 +29,7 class IssueStatusesController < ApplicationController
29 render :action => "index", :layout => false if request.xhr?
29 render :action => "index", :layout => false if request.xhr?
30 }
30 }
31 format.api {
31 format.api {
32 @issue_statuses = IssueStatus.order('position').all
32 @issue_statuses = IssueStatus.order('position').to_a
33 }
33 }
34 end
34 end
35 end
35 end
@@ -104,15 +104,16 class IssuesController < ApplicationController
104 end
104 end
105
105
106 def show
106 def show
107 @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all
107 @journals = @issue.journals.includes(:user, :details).
108 references(:user, :details).
109 reorder("#{Journal.table_name}.id ASC").to_a
108 @journals.each_with_index {|j,i| j.indice = i+1}
110 @journals.each_with_index {|j,i| j.indice = i+1}
109 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
111 @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
110 Journal.preload_journals_details_custom_fields(@journals)
112 Journal.preload_journals_details_custom_fields(@journals)
111 # TODO: use #select! when ruby1.8 support is dropped
113 @journals.select! {|journal| journal.notes? || journal.visible_details.any?}
112 @journals.reject! {|journal| !journal.notes? && journal.visible_details.empty?}
113 @journals.reverse! if User.current.wants_comments_in_reverse_order?
114 @journals.reverse! if User.current.wants_comments_in_reverse_order?
114
115
115 @changesets = @issue.changesets.visible.all
116 @changesets = @issue.changesets.visible.to_a
116 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
117 @changesets.reverse! if User.current.wants_comments_in_reverse_order?
117
118
118 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
119 @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
@@ -189,7 +190,7 class IssuesController < ApplicationController
189 rescue ActiveRecord::StaleObjectError
190 rescue ActiveRecord::StaleObjectError
190 @conflict = true
191 @conflict = true
191 if params[:last_journal_id]
192 if params[:last_journal_id]
192 @conflict_journals = @issue.journals_after(params[:last_journal_id]).all
193 @conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a
193 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
194 @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
194 end
195 end
195 end
196 end
@@ -301,7 +302,7 class IssuesController < ApplicationController
301 else
302 else
302 @saved_issues = @issues
303 @saved_issues = @issues
303 @unsaved_issues = unsaved_issues
304 @unsaved_issues = unsaved_issues
304 @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).all
305 @issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a
305 bulk_edit
306 bulk_edit
306 render :action => 'bulk_edit'
307 render :action => 'bulk_edit'
307 end
308 end
@@ -375,7 +376,9 class IssuesController < ApplicationController
375 def update_issue_from_params
376 def update_issue_from_params
376 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
377 @edit_allowed = User.current.allowed_to?(:edit_issues, @project)
377 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
378 @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
379 if params[:time_entry]
378 @time_entry.attributes = params[:time_entry]
380 @time_entry.attributes = params[:time_entry]
381 end
379
382
380 @issue.init_journal(User.current)
383 @issue.init_journal(User.current)
381
384
@@ -422,7 +425,9 class IssuesController < ApplicationController
422 @issue.project = @project
425 @issue.project = @project
423 @issue.author ||= User.current
426 @issue.author ||= User.current
424 # Tracker must be set before custom field values
427 # Tracker must be set before custom field values
425 @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
428 tracker_id = (params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id]
429 tracker = tracker_id.present? ? @project.trackers.find(tracker_id) : @project.trackers.first
430 @issue.tracker ||= tracker
426 if @issue.tracker.nil?
431 if @issue.tracker.nil?
427 render_error l(:error_no_tracker_in_project)
432 render_error l(:error_no_tracker_in_project)
428 return false
433 return false
@@ -34,7 +34,6 class JournalsController < ApplicationController
34 retrieve_query
34 retrieve_query
35 sort_init 'id', 'desc'
35 sort_init 'id', 'desc'
36 sort_update(@query.sortable_columns)
36 sort_update(@query.sortable_columns)
37
38 if @query.valid?
37 if @query.valid?
39 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
38 @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
40 :limit => 25)
39 :limit => 25)
@@ -32,7 +32,7 class MembersController < ApplicationController
32 order("#{Member.table_name}.id").
32 order("#{Member.table_name}.id").
33 limit(@limit).
33 limit(@limit).
34 offset(@offset).
34 offset(@offset).
35 all
35 to_a
36 respond_to do |format|
36 respond_to do |format|
37 format.html { head 406 }
37 format.html { head 406 }
38 format.api
38 format.api
@@ -63,7 +63,10 class MembersController < ApplicationController
63
63
64 respond_to do |format|
64 respond_to do |format|
65 format.html { redirect_to_settings_in_projects }
65 format.html { redirect_to_settings_in_projects }
66 format.js { @members = members }
66 format.js {
67 @members = members
68 @member = Member.new
69 }
67 format.api {
70 format.api {
68 @member = members.first
71 @member = members.first
69 if @member.valid?
72 if @member.valid?
@@ -43,10 +43,10 class MessagesController < ApplicationController
43 @reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page
43 @reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page
44 @replies = @topic.children.
44 @replies = @topic.children.
45 includes(:author, :attachments, {:board => :project}).
45 includes(:author, :attachments, {:board => :project}).
46 reorder("#{Message.table_name}.created_on ASC").
46 reorder("#{Message.table_name}.created_on ASC, #{Message.table_name}.id ASC").
47 limit(@reply_pages.per_page).
47 limit(@reply_pages.per_page).
48 offset(@reply_pages.offset).
48 offset(@reply_pages.offset).
49 all
49 to_a
50
50
51 @reply = Message.new(:subject => "RE: #{@message.subject}")
51 @reply = Message.new(:subject => "RE: #{@message.subject}")
52 render :action => "show", :layout => false if request.xhr?
52 render :action => "show", :layout => false if request.xhr?
@@ -53,8 +53,8 class MyController < ApplicationController
53 @user = User.current
53 @user = User.current
54 @pref = @user.pref
54 @pref = @user.pref
55 if request.post?
55 if request.post?
56 @user.safe_attributes = params[:user]
56 @user.safe_attributes = params[:user] if params[:user]
57 @user.pref.attributes = params[:pref]
57 @user.pref.attributes = params[:pref] if params[:pref]
58 if @user.save
58 if @user.save
59 @user.pref.save
59 @user.pref.save
60 set_language_if_valid @user.language
60 set_language_if_valid @user.language
@@ -46,7 +46,7 class NewsController < ApplicationController
46 order("#{News.table_name}.created_on DESC").
46 order("#{News.table_name}.created_on DESC").
47 limit(@limit).
47 limit(@limit).
48 offset(@offset).
48 offset(@offset).
49 all
49 to_a
50 respond_to do |format|
50 respond_to do |format|
51 format.html {
51 format.html {
52 @news = News.new # for adding news inline
52 @news = News.new # for adding news inline
@@ -20,7 +20,7 class ProjectEnumerationsController < ApplicationController
20 before_filter :authorize
20 before_filter :authorize
21
21
22 def update
22 def update
23 if request.put? && params[:enumerations]
23 if params[:enumerations]
24 Project.transaction do
24 Project.transaction do
25 params[:enumerations].each do |id, activity|
25 params[:enumerations].each do |id, activity|
26 @project.update_or_create_time_entry_activity(id, activity)
26 @project.update_or_create_time_entry_activity(id, activity)
@@ -53,30 +53,30 class ProjectsController < ApplicationController
53 unless params[:closed]
53 unless params[:closed]
54 scope = scope.active
54 scope = scope.active
55 end
55 end
56 @projects = scope.visible.order('lft').all
56 @projects = scope.visible.order('lft').to_a
57 }
57 }
58 format.api {
58 format.api {
59 @offset, @limit = api_offset_and_limit
59 @offset, @limit = api_offset_and_limit
60 @project_count = Project.visible.count
60 @project_count = Project.visible.count
61 @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
61 @projects = Project.visible.offset(@offset).limit(@limit).order('lft').to_a
62 }
62 }
63 format.atom {
63 format.atom {
64 projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
64 projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).to_a
65 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
65 render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
66 }
66 }
67 end
67 end
68 end
68 end
69
69
70 def new
70 def new
71 @issue_custom_fields = IssueCustomField.sorted.all
71 @issue_custom_fields = IssueCustomField.sorted.to_a
72 @trackers = Tracker.sorted.all
72 @trackers = Tracker.sorted.to_a
73 @project = Project.new
73 @project = Project.new
74 @project.safe_attributes = params[:project]
74 @project.safe_attributes = params[:project]
75 end
75 end
76
76
77 def create
77 def create
78 @issue_custom_fields = IssueCustomField.sorted.all
78 @issue_custom_fields = IssueCustomField.sorted.to_a
79 @trackers = Tracker.sorted.all
79 @trackers = Tracker.sorted.to_a
80 @project = Project.new
80 @project = Project.new
81 @project.safe_attributes = params[:project]
81 @project.safe_attributes = params[:project]
82
82
@@ -109,8 +109,8 class ProjectsController < ApplicationController
109 end
109 end
110
110
111 def copy
111 def copy
112 @issue_custom_fields = IssueCustomField.sorted.all
112 @issue_custom_fields = IssueCustomField.sorted.to_a
113 @trackers = Tracker.sorted.all
113 @trackers = Tracker.sorted.to_a
114 @source_project = Project.find(params[:id])
114 @source_project = Project.find(params[:id])
115 if request.get?
115 if request.get?
116 @project = Project.copy_from(@source_project)
116 @project = Project.copy_from(@source_project)
@@ -145,8 +145,8 class ProjectsController < ApplicationController
145 end
145 end
146
146
147 @users_by_role = @project.users_by_role
147 @users_by_role = @project.users_by_role
148 @subprojects = @project.children.visible.all
148 @subprojects = @project.children.visible.to_a
149 @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
149 @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").to_a
150 @trackers = @project.rolled_up_trackers
150 @trackers = @project.rolled_up_trackers
151
151
152 cond = @project.project_condition(Setting.display_subprojects_issues?)
152 cond = @project.project_condition(Setting.display_subprojects_issues?)
@@ -167,10 +167,10 class ProjectsController < ApplicationController
167 end
167 end
168
168
169 def settings
169 def settings
170 @issue_custom_fields = IssueCustomField.sorted.all
170 @issue_custom_fields = IssueCustomField.sorted.to_a
171 @issue_category ||= IssueCategory.new
171 @issue_category ||= IssueCategory.new
172 @member ||= @project.members.new
172 @member ||= @project.members.new
173 @trackers = Tracker.sorted.all
173 @trackers = Tracker.sorted.to_a
174 @wiki ||= @project.wiki
174 @wiki ||= @project.wiki
175 end
175 end
176
176
@@ -37,8 +37,9 class QueriesController < ApplicationController
37 order("#{Query.table_name}.name").
37 order("#{Query.table_name}.name").
38 limit(@limit).
38 limit(@limit).
39 offset(@offset).
39 offset(@offset).
40 all
40 to_a
41 respond_to do |format|
41 respond_to do |format|
42 format.html {render_error :status => 406}
42 format.api
43 format.api
43 end
44 end
44 end
45 end
@@ -90,6 +90,6 class ReportsController < ApplicationController
90 private
90 private
91
91
92 def find_issue_statuses
92 def find_issue_statuses
93 @statuses = IssueStatus.sorted.all
93 @statuses = IssueStatus.sorted.to_a
94 end
94 end
95 end
95 end
@@ -69,7 +69,7 class RepositoriesController < ApplicationController
69 @repository.merge_extra_info(attrs[:attrs_extra])
69 @repository.merge_extra_info(attrs[:attrs_extra])
70 end
70 end
71 @repository.project = @project
71 @repository.project = @project
72 if request.put? && @repository.save
72 if @repository.save
73 redirect_to settings_project_path(@project, :tab => 'repositories')
73 redirect_to settings_project_path(@project, :tab => 'repositories')
74 else
74 else
75 render :action => 'edit'
75 render :action => 'edit'
@@ -94,7 +94,7 class RepositoriesController < ApplicationController
94 @committers = @repository.committers
94 @committers = @repository.committers
95 @users = @project.users
95 @users = @project.users
96 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
96 additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
97 @users += User.where(:id => additional_user_ids).all unless additional_user_ids.empty?
97 @users += User.where(:id => additional_user_ids).to_a unless additional_user_ids.empty?
98 @users.compact!
98 @users.compact!
99 @users.sort!
99 @users.sort!
100 if request.post? && params[:committers].is_a?(Hash)
100 if request.post? && params[:committers].is_a?(Hash)
@@ -145,7 +145,7 class RepositoriesController < ApplicationController
145 limit(@changeset_pages.per_page).
145 limit(@changeset_pages.per_page).
146 offset(@changeset_pages.offset).
146 offset(@changeset_pages.offset).
147 includes(:user, :repository, :parents).
147 includes(:user, :repository, :parents).
148 all
148 to_a
149
149
150 respond_to do |format|
150 respond_to do |format|
151 format.html { render :layout => false if request.xhr? }
151 format.html { render :layout => false if request.xhr? }
@@ -30,7 +30,7 class RolesController < ApplicationController
30 render :action => "index", :layout => false if request.xhr?
30 render :action => "index", :layout => false if request.xhr?
31 }
31 }
32 format.api {
32 format.api {
33 @roles = Role.givable.all
33 @roles = Role.givable.to_a
34 }
34 }
35 end
35 end
36 end
36 end
@@ -47,7 +47,7 class RolesController < ApplicationController
47 if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy])
47 if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy])
48 @role.copy_from(@copy_from)
48 @role.copy_from(@copy_from)
49 end
49 end
50 @roles = Role.sorted.all
50 @roles = Role.sorted.to_a
51 end
51 end
52
52
53 def create
53 def create
@@ -60,7 +60,7 class RolesController < ApplicationController
60 flash[:notice] = l(:notice_successful_create)
60 flash[:notice] = l(:notice_successful_create)
61 redirect_to roles_path
61 redirect_to roles_path
62 else
62 else
63 @roles = Role.sorted.all
63 @roles = Role.sorted.to_a
64 render :action => 'new'
64 render :action => 'new'
65 end
65 end
66 end
66 end
@@ -69,7 +69,7 class RolesController < ApplicationController
69 end
69 end
70
70
71 def update
71 def update
72 if request.put? and @role.update_attributes(params[:role])
72 if @role.update_attributes(params[:role])
73 flash[:notice] = l(:notice_successful_update)
73 flash[:notice] = l(:notice_successful_update)
74 redirect_to roles_path
74 redirect_to roles_path
75 else
75 else
@@ -86,7 +86,7 class RolesController < ApplicationController
86 end
86 end
87
87
88 def permissions
88 def permissions
89 @roles = Role.sorted.all
89 @roles = Role.sorted.to_a
90 @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? }
90 @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? }
91 if request.post?
91 if request.post?
92 @roles.each do |role|
92 @roles.each do |role|
@@ -31,7 +31,7 class SearchController < ApplicationController
31 when 'my_projects'
31 when 'my_projects'
32 User.current.memberships.collect(&:project)
32 User.current.memberships.collect(&:project)
33 when 'subprojects'
33 when 'subprojects'
34 @project ? (@project.self_and_descendants.active.all) : nil
34 @project ? (@project.self_and_descendants.active.to_a) : nil
35 else
35 else
36 @project
36 @project
37 end
37 end
@@ -19,7 +19,8 class SysController < ActionController::Base
19 before_filter :check_enabled
19 before_filter :check_enabled
20
20
21 def projects
21 def projects
22 p = Project.active.has_module(:repository).order("#{Project.table_name}.identifier").preload(:repository).all
22 p = Project.active.has_module(:repository).
23 order("#{Project.table_name}.identifier").preload(:repository).to_a
23 # extra_info attribute from repository breaks activeresource client
24 # extra_info attribute from repository breaks activeresource client
24 render :xml => p.to_xml(
25 render :xml => p.to_xml(
25 :only => [:id, :identifier, :name, :is_public, :status],
26 :only => [:id, :identifier, :name, :is_public, :status],
@@ -56,7 +57,7 class SysController < ActionController::Base
56 raise ActiveRecord::RecordNotFound unless project
57 raise ActiveRecord::RecordNotFound unless project
57 projects << project
58 projects << project
58 else
59 else
59 projects = scope.all
60 projects = scope.to_a
60 end
61 end
61 projects.each do |project|
62 projects.each do |project|
62 project.repositories.each do |repository|
63 project.repositories.each do |repository|
@@ -52,7 +52,7 class TimelogController < ApplicationController
52 format.html {
52 format.html {
53 @entry_count = scope.count
53 @entry_count = scope.count
54 @entry_pages = Paginator.new @entry_count, per_page_option, params['page']
54 @entry_pages = Paginator.new @entry_count, per_page_option, params['page']
55 @entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).all
55 @entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a
56 @total_hours = scope.sum(:hours).to_f
56 @total_hours = scope.sum(:hours).to_f
57
57
58 render :layout => !request.xhr?
58 render :layout => !request.xhr?
@@ -60,15 +60,15 class TimelogController < ApplicationController
60 format.api {
60 format.api {
61 @entry_count = scope.count
61 @entry_count = scope.count
62 @offset, @limit = api_offset_and_limit
62 @offset, @limit = api_offset_and_limit
63 @entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).all
63 @entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).to_a
64 }
64 }
65 format.atom {
65 format.atom {
66 entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").all
66 entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").to_a
67 render_feed(entries, :title => l(:label_spent_time))
67 render_feed(entries, :title => l(:label_spent_time))
68 }
68 }
69 format.csv {
69 format.csv {
70 # Export all entries
70 # Export all entries
71 @entries = scope.all
71 @entries = scope.to_a
72 send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
72 send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
73 }
73 }
74 end
74 end
@@ -232,7 +232,7 private
232 end
232 end
233
233
234 def find_time_entries
234 def find_time_entries
235 @time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).all
235 @time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).to_a
236 raise ActiveRecord::RecordNotFound if @time_entries.empty?
236 raise ActiveRecord::RecordNotFound if @time_entries.empty?
237 @projects = @time_entries.collect(&:project).compact.uniq
237 @projects = @time_entries.collect(&:project).compact.uniq
238 @project = @projects.first if @projects.size == 1
238 @project = @projects.first if @projects.size == 1
@@ -29,14 +29,14 class TrackersController < ApplicationController
29 render :action => "index", :layout => false if request.xhr?
29 render :action => "index", :layout => false if request.xhr?
30 }
30 }
31 format.api {
31 format.api {
32 @trackers = Tracker.sorted.all
32 @trackers = Tracker.sorted.to_a
33 }
33 }
34 end
34 end
35 end
35 end
36
36
37 def new
37 def new
38 @tracker ||= Tracker.new(params[:tracker])
38 @tracker ||= Tracker.new(params[:tracker])
39 @trackers = Tracker.sorted.all
39 @trackers = Tracker.sorted.to_a
40 @projects = Project.all
40 @projects = Project.all
41 end
41 end
42
42
@@ -95,7 +95,7 class TrackersController < ApplicationController
95 redirect_to fields_trackers_path
95 redirect_to fields_trackers_path
96 return
96 return
97 end
97 end
98 @trackers = Tracker.sorted.all
98 @trackers = Tracker.sorted.to_a
99 @custom_fields = IssueCustomField.all.sort
99 @custom_fields = IssueCustomField.all.sort
100 end
100 end
101 end
101 end
@@ -47,7 +47,7 class UsersController < ApplicationController
47 @user_count = scope.count
47 @user_count = scope.count
48 @user_pages = Paginator.new @user_count, @limit, params['page']
48 @user_pages = Paginator.new @user_count, @limit, params['page']
49 @offset ||= @user_pages.offset
49 @offset ||= @user_pages.offset
50 @users = scope.order(sort_clause).limit(@limit).offset(@offset).all
50 @users = scope.order(sort_clause).limit(@limit).offset(@offset).to_a
51
51
52 respond_to do |format|
52 respond_to do |format|
53 format.html {
53 format.html {
@@ -60,7 +60,7 class UsersController < ApplicationController
60
60
61 def show
61 def show
62 # show projects based on current user visibility
62 # show projects based on current user visibility
63 @memberships = @user.memberships.where(Project.visible_condition(User.current)).all
63 @memberships = @user.memberships.where(Project.visible_condition(User.current)).to_a
64
64
65 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
65 events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
66 @events_by_day = events.group_by(&:event_date)
66 @events_by_day = events.group_by(&:event_date)
@@ -90,7 +90,7 class UsersController < ApplicationController
90 @user.admin = params[:user][:admin] || false
90 @user.admin = params[:user][:admin] || false
91 @user.login = params[:user][:login]
91 @user.login = params[:user][:login]
92 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
92 @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
93 @user.pref.attributes = params[:pref]
93 @user.pref.attributes = params[:pref] if params[:pref]
94
94
95 if @user.save
95 if @user.save
96 Mailer.account_information(@user, @user.password).deliver if params[:send_information]
96 Mailer.account_information(@user, @user.password).deliver if params[:send_information]
@@ -134,7 +134,7 class UsersController < ApplicationController
134 # Was the account actived ? (do it before User#save clears the change)
134 # Was the account actived ? (do it before User#save clears the change)
135 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
135 was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
136 # TODO: Similar to My#account
136 # TODO: Similar to My#account
137 @user.pref.attributes = params[:pref]
137 @user.pref.attributes = params[:pref] if params[:pref]
138
138
139 if @user.save
139 if @user.save
140 @user.pref.save
140 @user.pref.save
@@ -31,7 +31,7 class VersionsController < ApplicationController
31 def index
31 def index
32 respond_to do |format|
32 respond_to do |format|
33 format.html {
33 format.html {
34 @trackers = @project.trackers.sorted.all
34 @trackers = @project.trackers.sorted.to_a
35 retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
35 retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
36 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
36 @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
37 project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
37 project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
@@ -56,7 +56,7 class VersionsController < ApplicationController
56 @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
56 @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
57 }
57 }
58 format.api {
58 format.api {
59 @versions = @project.shared_versions.all
59 @versions = @project.shared_versions.to_a
60 }
60 }
61 end
61 end
62 end
62 end
@@ -67,7 +67,7 class VersionsController < ApplicationController
67 @issues = @version.fixed_issues.visible.
67 @issues = @version.fixed_issues.visible.
68 includes(:status, :tracker, :priority).
68 includes(:status, :tracker, :priority).
69 reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
69 reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
70 all
70 to_a
71 }
71 }
72 format.api
72 format.api
73 end
73 end
@@ -117,7 +117,7 class VersionsController < ApplicationController
117 end
117 end
118
118
119 def update
119 def update
120 if request.put? && params[:version]
120 if params[:version]
121 attributes = params[:version].dup
121 attributes = params[:version].dup
122 attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
122 attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
123 @version.safe_attributes = attributes
123 @version.safe_attributes = attributes
@@ -53,7 +53,7 class WatchersController < ApplicationController
53 def append
53 def append
54 if params[:watcher].is_a?(Hash)
54 if params[:watcher].is_a?(Hash)
55 user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
55 user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
56 @users = User.active.where(:id => user_ids).all
56 @users = User.active.where(:id => user_ids).to_a
57 end
57 end
58 if @users.blank?
58 if @users.blank?
59 render :nothing => true
59 render :nothing => true
@@ -92,7 +92,7 class WatchersController < ApplicationController
92 def find_watchables
92 def find_watchables
93 klass = Object.const_get(params[:object_type].camelcase) rescue nil
93 klass = Object.const_get(params[:object_type].camelcase) rescue nil
94 if klass && klass.respond_to?('watched_by')
94 if klass && klass.respond_to?('watched_by')
95 @watchables = klass.where(:id => Array.wrap(params[:object_id])).all
95 @watchables = klass.where(:id => Array.wrap(params[:object_id])).to_a
96 raise Unauthorized if @watchables.any? {|w|
96 raise Unauthorized if @watchables.any? {|w|
97 if w.respond_to?(:visible?)
97 if w.respond_to?(:visible?)
98 !w.visible?
98 !w.visible?
@@ -219,7 +219,7 class WikiController < ApplicationController
219 reorder('version DESC').
219 reorder('version DESC').
220 limit(@version_pages.per_page + 1).
220 limit(@version_pages.per_page + 1).
221 offset(@version_pages.offset).
221 offset(@version_pages.offset).
222 all
222 to_a
223
223
224 render :layout => false if request.xhr?
224 render :layout => false if request.xhr?
225 end
225 end
@@ -280,7 +280,7 class WikiController < ApplicationController
280 @pages = @wiki.pages.
280 @pages = @wiki.pages.
281 order('title').
281 order('title').
282 includes([:content, {:attachments => :author}]).
282 includes([:content, {:attachments => :author}]).
283 all
283 to_a
284 respond_to do |format|
284 respond_to do |format|
285 format.html {
285 format.html {
286 export = render_to_string :action => 'export_multiple', :layout => false
286 export = render_to_string :action => 'export_multiple', :layout => false
@@ -327,7 +327,7 private
327 def find_existing_or_new_page
327 def find_existing_or_new_page
328 @page = @wiki.find_or_new_page(params[:id])
328 @page = @wiki.find_or_new_page(params[:id])
329 if @wiki.page_found_with_redirect?
329 if @wiki.page_found_with_redirect?
330 redirect_to params.update(:id => @page.title)
330 redirect_to_page @page
331 end
331 end
332 end
332 end
333
333
@@ -339,10 +339,14 private
339 return
339 return
340 end
340 end
341 if @wiki.page_found_with_redirect?
341 if @wiki.page_found_with_redirect?
342 redirect_to params.update(:id => @page.title)
342 redirect_to_page @page
343 end
343 end
344 end
344 end
345
345
346 def redirect_to_page(page)
347 redirect_to :action => action_name, :project_id => page.wiki.project, :id => page.title
348 end
349
346 # Returns true if the current user is allowed to edit the page, otherwise false
350 # Returns true if the current user is allowed to edit the page, otherwise false
347 def editable?(page = @page)
351 def editable?(page = @page)
348 page.editable_by?(User.current)
352 page.editable_by?(User.current)
@@ -360,6 +364,6 private
360 reorder("#{WikiPage.table_name}.title").
364 reorder("#{WikiPage.table_name}.title").
361 includes(:wiki => :project).
365 includes(:wiki => :project).
362 includes(:parent).
366 includes(:parent).
363 all
367 to_a
364 end
368 end
365 end
369 end
@@ -86,9 +86,9 class WorkflowsController < ApplicationController
86 @source_role = Role.find_by_id(params[:source_role_id].to_i)
86 @source_role = Role.find_by_id(params[:source_role_id].to_i)
87 end
87 end
88 @target_trackers = params[:target_tracker_ids].blank? ?
88 @target_trackers = params[:target_tracker_ids].blank? ?
89 nil : Tracker.where(:id => params[:target_tracker_ids]).all
89 nil : Tracker.where(:id => params[:target_tracker_ids]).to_a
90 @target_roles = params[:target_role_ids].blank? ?
90 @target_roles = params[:target_role_ids].blank? ?
91 nil : Role.where(:id => params[:target_role_ids]).all
91 nil : Role.where(:id => params[:target_role_ids]).to_a
92 if request.post?
92 if request.post?
93 if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
93 if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
94 flash.now[:error] = l(:error_workflow_copy_source)
94 flash.now[:error] = l(:error_workflow_copy_source)
@@ -113,9 +113,9 class WorkflowsController < ApplicationController
113 def find_roles
113 def find_roles
114 ids = Array.wrap(params[:role_id])
114 ids = Array.wrap(params[:role_id])
115 if ids == ['all']
115 if ids == ['all']
116 @roles = Role.sorted.all
116 @roles = Role.sorted.to_a
117 elsif ids.present?
117 elsif ids.present?
118 @roles = Role.where(:id => ids).all
118 @roles = Role.where(:id => ids).to_a
119 end
119 end
120 @roles = nil if @roles.blank?
120 @roles = nil if @roles.blank?
121 end
121 end
@@ -123,9 +123,9 class WorkflowsController < ApplicationController
123 def find_trackers
123 def find_trackers
124 ids = Array.wrap(params[:tracker_id])
124 ids = Array.wrap(params[:tracker_id])
125 if ids == ['all']
125 if ids == ['all']
126 @trackers = Tracker.sorted.all
126 @trackers = Tracker.sorted.to_a
127 elsif ids.present?
127 elsif ids.present?
128 @trackers = Tracker.where(:id => ids).all
128 @trackers = Tracker.where(:id => ids).to_a
129 end
129 end
130 @trackers = nil if @trackers.blank?
130 @trackers = nil if @trackers.blank?
131 end
131 end
@@ -135,6 +135,6 class WorkflowsController < ApplicationController
135 if @trackers && @used_statuses_only
135 if @trackers && @used_statuses_only
136 @statuses = @trackers.map(&:issue_statuses).flatten.uniq.sort.presence
136 @statuses = @trackers.map(&:issue_statuses).flatten.uniq.sort.presence
137 end
137 end
138 @statuses ||= IssueStatus.sorted.all
138 @statuses ||= IssueStatus.sorted.to_a
139 end
139 end
140 end
140 end
@@ -138,9 +138,7 module ApplicationHelper
138 if project.archived?
138 if project.archived?
139 h(project.name)
139 h(project.name)
140 elsif options.key?(:action)
140 elsif options.key?(:action)
141 ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
141 raise "#link_to_project no longer accepts :action option in Redmine 3.0"
142 url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
143 link_to project.name, url, html_options
144 else
142 else
145 link_to project.name, project_path(project, options), html_options
143 link_to project.name, project_path(project, options), html_options
146 end
144 end
@@ -157,13 +155,6 module ApplicationHelper
157 end
155 end
158 end
156 end
159
157
160 # Generates a link to a version
161 def link_to_version(version, options = {})
162 return '' unless version && version.is_a?(Version)
163 options = {:title => format_date(version.effective_date)}.merge(options)
164 link_to_if version.visible?, format_version_name(version), version_path(version), options
165 end
166
167 # Helper that formats object for html or text rendering
158 # Helper that formats object for html or text rendering
168 def format_object(object, html=true, &block)
159 def format_object(object, html=true, &block)
169 if block_given?
160 if block_given?
@@ -185,7 +176,7 module ApplicationHelper
185 when 'Project'
176 when 'Project'
186 html ? link_to_project(object) : object.to_s
177 html ? link_to_project(object) : object.to_s
187 when 'Version'
178 when 'Version'
188 html ? link_to_version(object) : object.to_s
179 html ? link_to(object.name, version_path(object)) : object.to_s
189 when 'TrueClass'
180 when 'TrueClass'
190 l(:general_text_Yes)
181 l(:general_text_Yes)
191 when 'FalseClass'
182 when 'FalseClass'
@@ -247,7 +238,7 module ApplicationHelper
247 end
238 end
248
239
249 def format_version_name(version)
240 def format_version_name(version)
250 if !version.shared? || version.project == @project
241 if version.project == @project
251 h(version)
242 h(version)
252 else
243 else
253 h("#{version.project} - #{version}")
244 h("#{version.project} - #{version}")
@@ -502,7 +493,7 module ApplicationHelper
502 h(Setting.app_title)
493 h(Setting.app_title)
503 else
494 else
504 b = []
495 b = []
505 ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
496 ancestors = (@project.root? ? [] : @project.ancestors.visible.to_a)
506 if ancestors.any?
497 if ancestors.any?
507 root = ancestors.shift
498 root = ancestors.shift
508 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
499 b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
@@ -1217,7 +1208,7 module ApplicationHelper
1217 source
1208 source
1218 end
1209 end
1219 end
1210 end
1220 super sources, options
1211 super *sources, options
1221 end
1212 end
1222
1213
1223 # Overrides Rails' image_tag with themes and plugins support.
1214 # Overrides Rails' image_tag with themes and plugins support.
@@ -1250,7 +1241,7 module ApplicationHelper
1250 end
1241 end
1251 end
1242 end
1252 end
1243 end
1253 super sources, options
1244 super *sources, options
1254 end
1245 end
1255
1246
1256 # TODO: remove this in 2.5.0
1247 # TODO: remove this in 2.5.0
@@ -1288,12 +1279,7 module ApplicationHelper
1288 end
1279 end
1289
1280
1290 def sanitize_anchor_name(anchor)
1281 def sanitize_anchor_name(anchor)
1291 if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
1292 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1282 anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1293 else
1294 # TODO: remove when ruby1.8 is no longer supported
1295 anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
1296 end
1297 end
1283 end
1298
1284
1299 # Returns the javascript tags that are included in the html layout head
1285 # Returns the javascript tags that are included in the html layout head
@@ -30,7 +30,7 module GroupsHelper
30 scope = User.active.sorted.not_in_group(group).like(params[:q])
30 scope = User.active.sorted.not_in_group(group).like(params[:q])
31 principal_count = scope.count
31 principal_count = scope.count
32 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
32 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
33 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
33 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a
34
34
35 s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
35 s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
36
36
@@ -63,7 +63,7 module IssuesHelper
63
63
64 def render_issue_subject_with_tree(issue)
64 def render_issue_subject_with_tree(issue)
65 s = ''
65 s = ''
66 ancestors = issue.root? ? [] : issue.ancestors.visible.all
66 ancestors = issue.root? ? [] : issue.ancestors.visible.to_a
67 ancestors.each do |ancestor|
67 ancestors.each do |ancestor|
68 s << '<div>' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id)))
68 s << '<div>' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id)))
69 end
69 end
@@ -204,7 +204,7 module IssuesHelper
204 order("#{Query.table_name}.name ASC").
204 order("#{Query.table_name}.name ASC").
205 # Project specific queries and global queries
205 # Project specific queries and global queries
206 where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]).
206 where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]).
207 all
207 to_a
208 end
208 end
209 @sidebar_queries
209 @sidebar_queries
210 end
210 end
@@ -408,7 +408,7 module IssuesHelper
408 if association
408 if association
409 record = association.class_name.constantize.find_by_id(id)
409 record = association.class_name.constantize.find_by_id(id)
410 if record
410 if record
411 record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding)
411 record.name.force_encoding('UTF-8')
412 return record.name
412 return record.name
413 end
413 end
414 end
414 end
@@ -22,7 +22,7 module MembersHelper
22 scope = Principal.active.sorted.not_member_of(project).like(params[:q])
22 scope = Principal.active.sorted.not_member_of(project).like(params[:q])
23 principal_count = scope.count
23 principal_count = scope.count
24 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
24 principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
25 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
25 principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a
26
26
27 s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
27 s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
28
28
@@ -23,11 +23,12 module MyHelper
23 where(:project_id => User.current.projects.map(&:id)).
23 where(:project_id => User.current.projects.map(&:id)).
24 where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
24 where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
25 includes(:project, :tracker, :priority, :assigned_to).
25 includes(:project, :tracker, :priority, :assigned_to).
26 all
26 references(:project, :tracker, :priority, :assigned_to).
27 to_a
27 end
28 end
28
29
29 def documents_items
30 def documents_items
30 Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all
31 Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).to_a
31 end
32 end
32
33
33 def issuesassignedtome_items
34 def issuesassignedtome_items
@@ -35,8 +36,9 module MyHelper
35 where(:assigned_to_id => ([User.current.id] + User.current.group_ids)).
36 where(:assigned_to_id => ([User.current.id] + User.current.group_ids)).
36 limit(10).
37 limit(10).
37 includes(:status, :project, :tracker, :priority).
38 includes(:status, :project, :tracker, :priority).
39 references(:status, :project, :tracker, :priority).
38 order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC").
40 order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC").
39 all
41 to_a
40 end
42 end
41
43
42 def issuesreportedbyme_items
44 def issuesreportedbyme_items
@@ -44,12 +46,13 module MyHelper
44 where(:author_id => User.current.id).
46 where(:author_id => User.current.id).
45 limit(10).
47 limit(10).
46 includes(:status, :project, :tracker).
48 includes(:status, :project, :tracker).
49 references(:status, :project, :tracker).
47 order("#{Issue.table_name}.updated_on DESC").
50 order("#{Issue.table_name}.updated_on DESC").
48 all
51 to_a
49 end
52 end
50
53
51 def issueswatched_items
54 def issueswatched_items
52 Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all
55 Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).to_a
53 end
56 end
54
57
55 def news_items
58 def news_items
@@ -57,15 +60,17 module MyHelper
57 where(:project_id => User.current.projects.map(&:id)).
60 where(:project_id => User.current.projects.map(&:id)).
58 limit(10).
61 limit(10).
59 includes(:project, :author).
62 includes(:project, :author).
63 references(:project, :author).
60 order("#{News.table_name}.created_on DESC").
64 order("#{News.table_name}.created_on DESC").
61 all
65 to_a
62 end
66 end
63
67
64 def timelog_items
68 def timelog_items
65 TimeEntry.
69 TimeEntry.
66 where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
70 where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
67 includes(:activity, :project, {:issue => [:tracker, :status]}).
71 joins(:activity, :project, {:issue => [:tracker, :status]}).
72 references(:activity, :project, {:issue => [:tracker, :status]}).
68 order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
73 order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
69 all
74 to_a
70 end
75 end
71 end
76 end
@@ -18,6 +18,11
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19
19
20 module ProjectsHelper
20 module ProjectsHelper
21 def link_to_version(version, options = {})
22 return '' unless version && version.is_a?(Version)
23 link_to_if version.visible?, format_version_name(version), version_path(version), options
24 end
25
21 def project_settings_tabs
26 def project_settings_tabs
22 tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
27 tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
23 {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
28 {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
@@ -143,7 +143,7 module QueriesHelper
143 end
143 end
144 end
144 end
145
145
146 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
146 export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
147 # csv header fields
147 # csv header fields
148 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
148 csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
149 # csv lines
149 # csv lines
@@ -29,7 +29,6 module SearchHelper
29 result << '...'
29 result << '...'
30 break
30 break
31 end
31 end
32 words = words.mb_chars
33 if i.even?
32 if i.even?
34 result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words)
33 result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words)
35 else
34 else
@@ -84,7 +84,8 module SortHelper
84 def to_sql
84 def to_sql
85 sql = @criteria.collect do |k,o|
85 sql = @criteria.collect do |k,o|
86 if s = @available_criteria[k]
86 if s = @available_criteria[k]
87 (o ? s.to_a : s.to_a.collect {|c| append_desc(c)})
87 s = [s] unless s.is_a?(Array)
88 (o ? s : s.collect {|c| append_desc(c)})
88 end
89 end
89 end.flatten.compact
90 end.flatten.compact
90 sql.blank? ? nil : sql
91 sql.blank? ? nil : sql
@@ -105,7 +105,7 module TimelogHelper
105
105
106 def report_to_csv(report)
106 def report_to_csv(report)
107 decimal_separator = l(:general_csv_decimal_separator)
107 decimal_separator = l(:general_csv_decimal_separator)
108 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
108 export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
109 # Column headers
109 # Column headers
110 headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) }
110 headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) }
111 headers += report.periods
111 headers += report.periods
@@ -27,6 +27,7 class Attachment < ActiveRecord::Base
27 validates_length_of :disk_filename, :maximum => 255
27 validates_length_of :disk_filename, :maximum => 255
28 validates_length_of :description, :maximum => 255
28 validates_length_of :description, :maximum => 255
29 validate :validate_max_file_size
29 validate :validate_max_file_size
30 attr_protected :id
30
31
31 acts_as_event :title => :filename,
32 acts_as_event :title => :filename,
32 :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
33 :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
@@ -34,16 +35,16 class Attachment < ActiveRecord::Base
34 acts_as_activity_provider :type => 'files',
35 acts_as_activity_provider :type => 'files',
35 :permission => :view_files,
36 :permission => :view_files,
36 :author_key => :author_id,
37 :author_key => :author_id,
37 :find_options => {:select => "#{Attachment.table_name}.*",
38 :scope => select("#{Attachment.table_name}.*").
38 :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
39 joins("LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
39 "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"}
40 "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )")
40
41
41 acts_as_activity_provider :type => 'documents',
42 acts_as_activity_provider :type => 'documents',
42 :permission => :view_documents,
43 :permission => :view_documents,
43 :author_key => :author_id,
44 :author_key => :author_id,
44 :find_options => {:select => "#{Attachment.table_name}.*",
45 :scope => select("#{Attachment.table_name}.*").
45 :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
46 joins("LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
46 "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
47 "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id")
47
48
48 cattr_accessor :storage_path
49 cattr_accessor :storage_path
49 @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files")
50 @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files")
@@ -74,7 +75,7 class Attachment < ActiveRecord::Base
74 if @temp_file.size > 0
75 if @temp_file.size > 0
75 if @temp_file.respond_to?(:original_filename)
76 if @temp_file.respond_to?(:original_filename)
76 self.filename = @temp_file.original_filename
77 self.filename = @temp_file.original_filename
77 self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding)
78 self.filename.force_encoding("UTF-8")
78 end
79 end
79 if @temp_file.respond_to?(:content_type)
80 if @temp_file.respond_to?(:content_type)
80 self.content_type = @temp_file.content_type.to_s.chomp
81 self.content_type = @temp_file.content_type.to_s.chomp
@@ -29,6 +29,7 class AuthSource < ActiveRecord::Base
29 validates_presence_of :name
29 validates_presence_of :name
30 validates_uniqueness_of :name
30 validates_uniqueness_of :name
31 validates_length_of :name, :maximum => 60
31 validates_length_of :name, :maximum => 60
32 attr_protected :id
32
33
33 def authenticate(login, password)
34 def authenticate(login, password)
34 end
35 end
@@ -18,8 +18,8
18 class Board < ActiveRecord::Base
18 class Board < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 belongs_to :project
20 belongs_to :project
21 has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
21 has_many :topics, lambda {where("#{Message.table_name}.parent_id IS NULL").order("#{Message.table_name}.created_on DESC")}, :class_name => 'Message'
22 has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
22 has_many :messages, lambda {order("#{Message.table_name}.created_on DESC")}, :dependent => :destroy
23 belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id
23 belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id
24 acts_as_tree :dependent => :nullify
24 acts_as_tree :dependent => :nullify
25 acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})'
25 acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})'
@@ -29,9 +29,12 class Board < ActiveRecord::Base
29 validates_length_of :name, :maximum => 30
29 validates_length_of :name, :maximum => 30
30 validates_length_of :description, :maximum => 255
30 validates_length_of :description, :maximum => 255
31 validate :validate_board
31 validate :validate_board
32 attr_protected :id
32
33
33 scope :visible, lambda {|*args|
34 scope :visible, lambda {|*args|
34 includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
35 joins(:project).
36 references(:project).
37 where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
35 }
38 }
36
39
37 safe_attributes 'name', 'description', 'parent_id', 'move_to'
40 safe_attributes 'name', 'description', 'parent_id', 'move_to'
@@ -21,6 +21,7 class Change < ActiveRecord::Base
21 validates_presence_of :changeset_id, :action, :path
21 validates_presence_of :changeset_id, :action, :path
22 before_save :init_path
22 before_save :init_path
23 before_validation :replace_invalid_utf8_of_path
23 before_validation :replace_invalid_utf8_of_path
24 attr_protected :id
24
25
25 def relative_path
26 def relative_path
26 changeset.repository.relative_path(path)
27 changeset.repository.relative_path(path)
@@ -35,20 +35,23 class Changeset < ActiveRecord::Base
35 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
35 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
36
36
37 acts_as_searchable :columns => 'comments',
37 acts_as_searchable :columns => 'comments',
38 :include => {:repository => :project},
38 :scope => preload(:repository => :project),
39 :project_key => "#{Repository.table_name}.project_id",
39 :project_key => "#{Repository.table_name}.project_id",
40 :date_column => 'committed_on'
40 :date_column => 'committed_on'
41
41
42 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
42 acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
43 :author_key => :user_id,
43 :author_key => :user_id,
44 :find_options => {:include => [:user, {:repository => :project}]}
44 :scope => preload(:user, {:repository => :project})
45
45
46 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
46 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
47 validates_uniqueness_of :revision, :scope => :repository_id
47 validates_uniqueness_of :revision, :scope => :repository_id
48 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
48 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
49 attr_protected :id
49
50
50 scope :visible, lambda {|*args|
51 scope :visible, lambda {|*args|
51 includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
52 joins(:repository => :project).
53 references(:repository => :project).
54 where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
52 }
55 }
53
56
54 after_create :scan_for_issues
57 after_create :scan_for_issues
@@ -21,6 +21,7 class Comment < ActiveRecord::Base
21 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
22
22
23 validates_presence_of :commented, :author, :comments
23 validates_presence_of :commented, :author, :comments
24 attr_protected :id
24
25
25 after_create :send_notification
26 after_create :send_notification
26
27
@@ -29,6 +29,7 class CustomField < ActiveRecord::Base
29 validates_length_of :name, :maximum => 30
29 validates_length_of :name, :maximum => 30
30 validates_inclusion_of :field_format, :in => Proc.new { Redmine::FieldFormat.available_formats }
30 validates_inclusion_of :field_format, :in => Proc.new { Redmine::FieldFormat.available_formats }
31 validate :validate_custom_field
31 validate :validate_custom_field
32 attr_protected :id
32
33
33 before_validation :set_searchable
34 before_validation :set_searchable
34 before_save do |field|
35 before_save do |field|
@@ -117,7 +118,7 class CustomField < ActiveRecord::Base
117 values = read_attribute(:possible_values)
118 values = read_attribute(:possible_values)
118 if values.is_a?(Array)
119 if values.is_a?(Array)
119 values.each do |value|
120 values.each do |value|
120 value.force_encoding('UTF-8') if value.respond_to?(:force_encoding)
121 value.force_encoding('UTF-8')
121 end
122 end
122 values
123 values
123 else
124 else
@@ -218,7 +219,7 class CustomField < ActiveRecord::Base
218
219
219 # to move in project_custom_field
220 # to move in project_custom_field
220 def self.for_all
221 def self.for_all
221 where(:is_for_all => true).order('position').all
222 where(:is_for_all => true).order('position').to_a
222 end
223 end
223
224
224 def type_name
225 def type_name
@@ -18,6 +18,7
18 class CustomValue < ActiveRecord::Base
18 class CustomValue < ActiveRecord::Base
19 belongs_to :custom_field
19 belongs_to :custom_field
20 belongs_to :customized, :polymorphic => true
20 belongs_to :customized, :polymorphic => true
21 attr_protected :id
21
22
22 def initialize(attributes=nil, *args)
23 def initialize(attributes=nil, *args)
23 super
24 super
@@ -21,19 +21,23 class Document < ActiveRecord::Base
21 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
21 belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
22 acts_as_attachable :delete_permission => :delete_documents
22 acts_as_attachable :delete_permission => :delete_documents
23
23
24 acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
24 acts_as_searchable :columns => ['title', "#{table_name}.description"],
25 :scope => preload(:project)
25 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
26 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
26 :author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
27 :author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
27 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
28 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
28 acts_as_activity_provider :find_options => {:include => :project}
29 acts_as_activity_provider :scope => preload(:project)
29
30
30 validates_presence_of :project, :title, :category
31 validates_presence_of :project, :title, :category
31 validates_length_of :title, :maximum => 60
32 validates_length_of :title, :maximum => 60
33 attr_protected :id
32
34
33 after_create :send_notification
35 after_create :send_notification
34
36
35 scope :visible, lambda {|*args|
37 scope :visible, lambda {|*args|
36 includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
38 joins(:project).
39 references(:project).
40 where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
37 }
41 }
38
42
39 safe_attributes 'category_id', 'title', 'description'
43 safe_attributes 'category_id', 'title', 'description'
@@ -21,6 +21,7 class EnabledModule < ActiveRecord::Base
21
21
22 validates_presence_of :name
22 validates_presence_of :name
23 validates_uniqueness_of :name, :scope => :project_id
23 validates_uniqueness_of :name, :scope => :project_id
24 attr_protected :id
24
25
25 after_create :module_enabled
26 after_create :module_enabled
26
27
@@ -18,7 +18,7
18 class Enumeration < ActiveRecord::Base
18 class Enumeration < ActiveRecord::Base
19 include Redmine::SubclassFactory
19 include Redmine::SubclassFactory
20
20
21 default_scope :order => "#{Enumeration.table_name}.position ASC"
21 default_scope lambda {order("#{Enumeration.table_name}.position ASC")}
22
22
23 belongs_to :project
23 belongs_to :project
24
24
@@ -28,6 +28,7 class Group < Principal
28 validates_presence_of :lastname
28 validates_presence_of :lastname
29 validates_uniqueness_of :lastname, :case_sensitive => false
29 validates_uniqueness_of :lastname, :case_sensitive => false
30 validates_length_of :lastname, :maximum => 255
30 validates_length_of :lastname, :maximum => 255
31 attr_protected :id
31
32
32 before_destroy :remove_references_before_destroy
33 before_destroy :remove_references_before_destroy
33
34
@@ -81,7 +82,8 class Group < Principal
81 def user_removed(user)
82 def user_removed(user)
82 members.each do |member|
83 members.each do |member|
83 MemberRole.
84 MemberRole.
84 includes(:member).
85 joins(:member).
86 references(:member).
85 where("#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids).
87 where("#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids).
86 each(&:destroy)
88 each(&:destroy)
87 end
89 end
@@ -95,10 +97,6 class Group < Principal
95 super(attr_name, *args)
97 super(attr_name, *args)
96 end
98 end
97
99
98 def self.builtin_id(arg)
99 (arg.anonymous? ? GroupAnonymous : GroupNonMember).instance_id
100 end
101
102 def self.anonymous
100 def self.anonymous
103 GroupAnonymous.load_instance
101 GroupAnonymous.load_instance
104 end
102 end
@@ -23,8 +23,4 class GroupAnonymous < GroupBuiltin
23 def builtin_type
23 def builtin_type
24 "anonymous"
24 "anonymous"
25 end
25 end
26
27 def self.instance_id
28 @@instance_id ||= load_instance.id
29 end
30 end
26 end
@@ -37,7 +37,7 class GroupBuiltin < Group
37 class << self
37 class << self
38 def load_instance
38 def load_instance
39 return nil if self == GroupBuiltin
39 return nil if self == GroupBuiltin
40 instance = first(:order => 'id') || create_instance
40 instance = order('id').first || create_instance
41 end
41 end
42
42
43 def create_instance
43 def create_instance
@@ -23,8 +23,4 class GroupNonMember < GroupBuiltin
23 def builtin_type
23 def builtin_type
24 "non_member"
24 "non_member"
25 end
25 end
26
27 def self.instance_id
28 @@instance_id ||= load_instance.id
29 end
30 end
26 end
@@ -31,15 +31,12 class Issue < ActiveRecord::Base
31
31
32 has_many :journals, :as => :journalized, :dependent => :destroy
32 has_many :journals, :as => :journalized, :dependent => :destroy
33 has_many :visible_journals,
33 has_many :visible_journals,
34 lambda {where(["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false])},
34 :class_name => 'Journal',
35 :class_name => 'Journal',
35 :as => :journalized,
36 :as => :journalized
36 :conditions => Proc.new {
37 ["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false]
38 },
39 :readonly => true
40
37
41 has_many :time_entries, :dependent => :destroy
38 has_many :time_entries, :dependent => :destroy
42 has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC"
39 has_and_belongs_to_many :changesets, lambda {order("#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC")}
43
40
44 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
41 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
45 has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
42 has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
@@ -49,14 +46,19 class Issue < ActiveRecord::Base
49 acts_as_customizable
46 acts_as_customizable
50 acts_as_watchable
47 acts_as_watchable
51 acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
48 acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
52 :include => [:project, :visible_journals],
53 # sort by id so that limited eager loading doesn't break with postgresql
49 # sort by id so that limited eager loading doesn't break with postgresql
54 :order_column => "#{table_name}.id"
50 :order_column => "#{table_name}.id",
51 :scope => lambda { joins(:project).
52 joins("LEFT OUTER JOIN #{Journal.table_name} ON #{Journal.table_name}.journalized_type='Issue'" +
53 " AND #{Journal.table_name}.journalized_id = #{Issue.table_name}.id" +
54 " AND (#{Journal.table_name}.private_notes = #{connection.quoted_false}" +
55 " OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))") }
56
55 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"},
57 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"},
56 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
58 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
57 :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
59 :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
58
60
59 acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]},
61 acts_as_activity_provider :scope => preload(:project, :author, :tracker),
60 :author_key => :author_id
62 :author_key => :author_id
61
63
62 DONE_RATIO_OPTIONS = %w(issue_field issue_status)
64 DONE_RATIO_OPTIONS = %w(issue_field issue_status)
@@ -72,19 +74,26 class Issue < ActiveRecord::Base
72 validates :start_date, :date => true
74 validates :start_date, :date => true
73 validates :due_date, :date => true
75 validates :due_date, :date => true
74 validate :validate_issue, :validate_required_fields
76 validate :validate_issue, :validate_required_fields
77 attr_protected :id
75
78
76 scope :visible, lambda {|*args|
79 scope :visible, lambda {|*args|
77 includes(:project).where(Issue.visible_condition(args.shift || User.current, *args))
80 joins(:project).
81 references(:project).
82 where(Issue.visible_condition(args.shift || User.current, *args))
78 }
83 }
79
84
80 scope :open, lambda {|*args|
85 scope :open, lambda {|*args|
81 is_closed = args.size > 0 ? !args.first : false
86 is_closed = args.size > 0 ? !args.first : false
82 includes(:status).where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
87 joins(:status).
88 references(:status).
89 where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
83 }
90 }
84
91
85 scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") }
92 scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") }
86 scope :on_active_project, lambda {
93 scope :on_active_project, lambda {
87 includes(:status, :project, :tracker).where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
94 joins(:project).
95 references(:project).
96 where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
88 }
97 }
89 scope :fixed_version, lambda {|versions|
98 scope :fixed_version, lambda {|versions|
90 ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v}
99 ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v}
@@ -107,7 +116,7 class Issue < ActiveRecord::Base
107 # Returns a SQL conditions string used to find all issues visible by the specified user
116 # Returns a SQL conditions string used to find all issues visible by the specified user
108 def self.visible_condition(user, options={})
117 def self.visible_condition(user, options={})
109 Project.allowed_to_condition(user, :view_issues, options) do |role, user|
118 Project.allowed_to_condition(user, :view_issues, options) do |role, user|
110 if user.logged?
119 if user.id && user.logged?
111 case role.issues_visibility
120 case role.issues_visibility
112 when 'all'
121 when 'all'
113 nil
122 nil
@@ -351,6 +360,10 class Issue < ActiveRecord::Base
351 # Do not redefine alias chain on reload (see #4838)
360 # Do not redefine alias chain on reload (see #4838)
352 alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first)
361 alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first)
353
362
363 def attributes=(new_attributes)
364 assign_attributes new_attributes
365 end
366
354 def estimated_hours=(h)
367 def estimated_hours=(h)
355 write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
368 write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
356 end
369 end
@@ -423,7 +436,7 class Issue < ActiveRecord::Base
423 def safe_attributes=(attrs, user=User.current)
436 def safe_attributes=(attrs, user=User.current)
424 return unless attrs.is_a?(Hash)
437 return unless attrs.is_a?(Hash)
425
438
426 attrs = attrs.dup
439 attrs = attrs.deep_dup
427
440
428 # Project and Tracker must be set before since new_statuses_allowed_to depends on it.
441 # Project and Tracker must be set before since new_statuses_allowed_to depends on it.
429 if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
442 if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
@@ -458,14 +471,12 class Issue < ActiveRecord::Base
458
471
459 if attrs['custom_field_values'].present?
472 if attrs['custom_field_values'].present?
460 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
473 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
461 # TODO: use #select when ruby1.8 support is dropped
474 attrs['custom_field_values'].select! {|k, v| editable_custom_field_ids.include?(k.to_s)}
462 attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| !editable_custom_field_ids.include?(k.to_s)}
463 end
475 end
464
476
465 if attrs['custom_fields'].present?
477 if attrs['custom_fields'].present?
466 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
478 editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
467 # TODO: use #select when ruby1.8 support is dropped
479 attrs['custom_fields'].select! {|c| editable_custom_field_ids.include?(c['id'].to_s)}
468 attrs['custom_fields'] = attrs['custom_fields'].reject {|c| !editable_custom_field_ids.include?(c['id'].to_s)}
469 end
480 end
470
481
471 # mass-assignment security bypass
482 # mass-assignment security bypass
@@ -733,7 +744,7 class Issue < ActiveRecord::Base
733 def assignable_versions
744 def assignable_versions
734 return @assignable_versions if @assignable_versions
745 return @assignable_versions if @assignable_versions
735
746
736 versions = project.shared_versions.open.all
747 versions = project.shared_versions.open.to_a
737 if fixed_version
748 if fixed_version
738 if fixed_version_id_changed?
749 if fixed_version_id_changed?
739 # nothing to do
750 # nothing to do
@@ -879,10 +890,14 class Issue < ActiveRecord::Base
879 if issues.any?
890 if issues.any?
880 issue_ids = issues.map(&:id)
891 issue_ids = issues.map(&:id)
881 # Relations with issue_from in given issues and visible issue_to
892 # Relations with issue_from in given issues and visible issue_to
882 relations_from = IssueRelation.includes(:issue_to => [:status, :project]).where(visible_condition(user)).where(:issue_from_id => issue_ids).all
893 relations_from = IssueRelation.joins(:issue_to => :project).
894 references(:issue_to => :project).
895 where(visible_condition(user)).where(:issue_from_id => issue_ids).to_a
883 # Relations with issue_to in given issues and visible issue_from
896 # Relations with issue_to in given issues and visible issue_from
884 relations_to = IssueRelation.includes(:issue_from => [:status, :project]).where(visible_condition(user)).where(:issue_to_id => issue_ids).all
897 relations_to = IssueRelation.joins(:issue_from => :project).
885
898 references(:issue_from => :project).
899 where(visible_condition(user)).
900 where(:issue_to_id => issue_ids).to_a
886 issues.each do |issue|
901 issues.each do |issue|
887 relations =
902 relations =
888 relations_from.select {|relation| relation.issue_from_id == issue.id} +
903 relations_from.select {|relation| relation.issue_from_id == issue.id} +
@@ -1121,6 +1136,7 class Issue < ActiveRecord::Base
1121 def parent_issue_id=(arg)
1136 def parent_issue_id=(arg)
1122 s = arg.to_s.strip.presence
1137 s = arg.to_s.strip.presence
1123 if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
1138 if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
1139 @parent_issue.id
1124 @invalid_parent_issue_id = nil
1140 @invalid_parent_issue_id = nil
1125 elsif s.blank?
1141 elsif s.blank?
1126 @parent_issue = nil
1142 @parent_issue = nil
@@ -1349,7 +1365,7 class Issue < ActiveRecord::Base
1349 self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
1365 self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
1350 cond = ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]
1366 cond = ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]
1351 self.class.base_class.select('id').lock(true).where(cond)
1367 self.class.base_class.select('id').lock(true).where(cond)
1352 offset = right_most_bound + 1 - lft
1368 offset = rdm_right_most_bound + 1 - lft
1353 Issue.where(cond).
1369 Issue.where(cond).
1354 update_all(["root_id = ?, lft = lft + ?, rgt = rgt + ?", root_id, offset, offset])
1370 update_all(["root_id = ?, lft = lft + ?, rgt = rgt + ?", root_id, offset, offset])
1355 end
1371 end
@@ -1367,6 +1383,14 class Issue < ActiveRecord::Base
1367 recalculate_attributes_for(former_parent_id) if former_parent_id
1383 recalculate_attributes_for(former_parent_id) if former_parent_id
1368 end
1384 end
1369
1385
1386 def rdm_right_most_bound
1387 right_most_node =
1388 self.class.base_class.unscoped.
1389 order("#{quoted_right_column_full_name} desc").limit(1).lock(true).first
1390 right_most_node ? (right_most_node[right_column_name] || 0 ) : 0
1391 end
1392 private :rdm_right_most_bound
1393
1370 def update_parent_attributes
1394 def update_parent_attributes
1371 recalculate_attributes_for(parent_id) if parent_id
1395 recalculate_attributes_for(parent_id) if parent_id
1372 end
1396 end
@@ -1395,7 +1419,7 class Issue < ActiveRecord::Base
1395 end
1419 end
1396 done = p.leaves.joins(:status).
1420 done = p.leaves.joins(:status).
1397 sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
1421 sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
1398 "* (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
1422 "* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
1399 progress = done / (average * leaves_count)
1423 progress = done / (average * leaves_count)
1400 p.done_ratio = progress.round
1424 p.done_ratio = progress.round
1401 end
1425 end
@@ -1415,7 +1439,8 class Issue < ActiveRecord::Base
1415 def self.update_versions(conditions=nil)
1439 def self.update_versions(conditions=nil)
1416 # Only need to update issues with a fixed_version from
1440 # Only need to update issues with a fixed_version from
1417 # a different project and that is not systemwide shared
1441 # a different project and that is not systemwide shared
1418 Issue.includes(:project, :fixed_version).
1442 Issue.joins(:project, :fixed_version).
1443 references(:version, :fixed_version).
1419 where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
1444 where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
1420 " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
1445 " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
1421 " AND #{Version.table_name}.sharing <> 'system'").
1446 " AND #{Version.table_name}.sharing <> 'system'").
@@ -24,6 +24,7 class IssueCategory < ActiveRecord::Base
24 validates_presence_of :name
24 validates_presence_of :name
25 validates_uniqueness_of :name, :scope => [:project_id]
25 validates_uniqueness_of :name, :scope => [:project_id]
26 validates_length_of :name, :maximum => 30
26 validates_length_of :name, :maximum => 30
27 attr_protected :id
27
28
28 safe_attributes 'name', 'assigned_to_id'
29 safe_attributes 'name', 'assigned_to_id'
29
30
@@ -32,7 +32,7 class IssueCustomField < CustomField
32 sql = super
32 sql = super
33 id_column ||= id
33 id_column ||= id
34 tracker_condition = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id_column})"
34 tracker_condition = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id_column})"
35 project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" +
35 project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{self.class.connection.quoted_true} AND ifa.id = #{id_column})" +
36 " OR #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id_column})"
36 " OR #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id_column})"
37
37
38 "((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
38 "((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
@@ -45,7 +45,9 class IssueQuery < Query
45 scope :visible, lambda {|*args|
45 scope :visible, lambda {|*args|
46 user = args.shift || User.current
46 user = args.shift || User.current
47 base = Project.allowed_to_condition(user, :view_issues, *args)
47 base = Project.allowed_to_condition(user, :view_issues, *args)
48 scope = includes(:project).where("#{table_name}.project_id IS NULL OR (#{base})")
48 scope = joins("LEFT OUTER JOIN #{Project.table_name} ON #{table_name}.project_id = #{Project.table_name}.id").
49 references(:project).
50 where("#{table_name}.project_id IS NULL OR (#{base})")
49
51
50 if user.admin?
52 if user.admin?
51 scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id)
53 scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id)
@@ -132,17 +134,17 class IssueQuery < Query
132 if project
134 if project
133 principals += project.principals.sort
135 principals += project.principals.sort
134 unless project.leaf?
136 unless project.leaf?
135 subprojects = project.descendants.visible.all
137 subprojects = project.descendants.visible.to_a
136 principals += Principal.member_of(subprojects)
138 principals += Principal.member_of(subprojects)
137 end
139 end
138 versions = project.shared_versions.all
140 versions = project.shared_versions.to_a
139 categories = project.issue_categories.all
141 categories = project.issue_categories.to_a
140 issue_custom_fields = project.all_issue_custom_fields
142 issue_custom_fields = project.all_issue_custom_fields
141 else
143 else
142 if all_projects.any?
144 if all_projects.any?
143 principals += Principal.member_of(all_projects)
145 principals += Principal.member_of(all_projects)
144 end
146 end
145 versions = Version.visible.where(:sharing => 'system').all
147 versions = Version.visible.where(:sharing => 'system').to_a
146 issue_custom_fields = IssueCustomField.where(:is_for_all => true)
148 issue_custom_fields = IssueCustomField.where(:is_for_all => true)
147 end
149 end
148 principals.uniq!
150 principals.uniq!
@@ -339,7 +341,7 class IssueQuery < Query
339 scope = scope.preload(:author)
341 scope = scope.preload(:author)
340 end
342 end
341
343
342 issues = scope.all
344 issues = scope.to_a
343
345
344 if has_column?(:spent_hours)
346 if has_column?(:spent_hours)
345 Issue.load_visible_spent_hours(issues)
347 Issue.load_visible_spent_hours(issues)
@@ -360,12 +362,13 class IssueQuery < Query
360 joins(:status, :project).
362 joins(:status, :project).
361 where(statement).
363 where(statement).
362 includes(([:status, :project] + (options[:include] || [])).uniq).
364 includes(([:status, :project] + (options[:include] || [])).uniq).
365 references(([:status, :project] + (options[:include] || [])).uniq).
363 where(options[:conditions]).
366 where(options[:conditions]).
364 order(order_option).
367 order(order_option).
365 joins(joins_for_order_statement(order_option.join(','))).
368 joins(joins_for_order_statement(order_option.join(','))).
366 limit(options[:limit]).
369 limit(options[:limit]).
367 offset(options[:offset]).
370 offset(options[:offset]).
368 find_ids
371 pluck(:id)
369 rescue ::ActiveRecord::StatementInvalid => e
372 rescue ::ActiveRecord::StatementInvalid => e
370 raise StatementInvalid.new(e.message)
373 raise StatementInvalid.new(e.message)
371 end
374 end
@@ -380,7 +383,7 class IssueQuery < Query
380 limit(options[:limit]).
383 limit(options[:limit]).
381 offset(options[:offset]).
384 offset(options[:offset]).
382 preload(:details, :user, {:issue => [:project, :author, :tracker, :status]}).
385 preload(:details, :user, {:issue => [:project, :author, :tracker, :status]}).
383 all
386 to_a
384 rescue ::ActiveRecord::StatementInvalid => e
387 rescue ::ActiveRecord::StatementInvalid => e
385 raise StatementInvalid.new(e.message)
388 raise StatementInvalid.new(e.message)
386 end
389 end
@@ -392,7 +395,8 class IssueQuery < Query
392 where(project_statement).
395 where(project_statement).
393 where(options[:conditions]).
396 where(options[:conditions]).
394 includes(:project).
397 includes(:project).
395 all
398 references(:project).
399 to_a
396 rescue ::ActiveRecord::StatementInvalid => e
400 rescue ::ActiveRecord::StatementInvalid => e
397 raise StatementInvalid.new(e.message)
401 raise StatementInvalid.new(e.message)
398 end
402 end
@@ -411,7 +415,7 class IssueQuery < Query
411 groups = Group.givable
415 groups = Group.givable
412 operator = '!' # Override the operator since we want to find by assigned_to
416 operator = '!' # Override the operator since we want to find by assigned_to
413 else
417 else
414 groups = Group.where(:id => value).all
418 groups = Group.where(:id => value).to_a
415 end
419 end
416 groups ||= []
420 groups ||= []
417
421
@@ -431,7 +435,7 class IssueQuery < Query
431 " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))"
435 " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))"
432 when "=", "!"
436 when "=", "!"
433 role_cond = value.any? ?
437 role_cond = value.any? ?
434 "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" :
438 "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")" :
435 "1=0"
439 "1=0"
436
440
437 sw = operator == "!" ? 'NOT' : ''
441 sw = operator == "!" ? 'NOT' : ''
@@ -443,7 +447,7 class IssueQuery < Query
443
447
444 def sql_for_is_private_field(field, operator, value)
448 def sql_for_is_private_field(field, operator, value)
445 op = (operator == "=" ? 'IN' : 'NOT IN')
449 op = (operator == "=" ? 'IN' : 'NOT IN')
446 va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',')
450 va = value.map {|v| v == '0' ? self.class.connection.quoted_false : self.class.connection.quoted_true}.uniq.join(',')
447
451
448 "#{Issue.table_name}.is_private #{op} (#{va})"
452 "#{Issue.table_name}.is_private #{op} (#{va})"
449 end
453 end
@@ -462,14 +466,14 class IssueQuery < Query
462 sql = case operator
466 sql = case operator
463 when "*", "!*"
467 when "*", "!*"
464 op = (operator == "*" ? 'IN' : 'NOT IN')
468 op = (operator == "*" ? 'IN' : 'NOT IN')
465 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}')"
469 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}')"
466 when "=", "!"
470 when "=", "!"
467 op = (operator == "=" ? 'IN' : 'NOT IN')
471 op = (operator == "=" ? 'IN' : 'NOT IN')
468 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = #{value.first.to_i})"
472 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = #{value.first.to_i})"
469 when "=p", "=!p", "!p"
473 when "=p", "=!p", "!p"
470 op = (operator == "!p" ? 'NOT IN' : 'IN')
474 op = (operator == "!p" ? 'NOT IN' : 'IN')
471 comp = (operator == "=!p" ? '<>' : '=')
475 comp = (operator == "=!p" ? '<>' : '=')
472 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})"
476 "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{self.class.connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})"
473 end
477 end
474
478
475 if relation_options[:sym] == field && !options[:reverse]
479 if relation_options[:sym] == field && !options[:reverse]
@@ -27,6 +27,7 class IssueStatus < ActiveRecord::Base
27 validates_uniqueness_of :name
27 validates_uniqueness_of :name
28 validates_length_of :name, :maximum => 30
28 validates_length_of :name, :maximum => 30
29 validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true
29 validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true
30 attr_protected :id
30
31
31 scope :sorted, lambda { order("#{table_name}.position ASC") }
32 scope :sorted, lambda { order("#{table_name}.position ASC") }
32 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
33 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
@@ -79,7 +80,7 class IssueStatus < ActiveRecord::Base
79 includes(:new_status).
80 includes(:new_status).
80 where(["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})",
81 where(["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})",
81 {:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false}
82 {:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false}
82 ]).all.
83 ]).to_a.
83 map(&:new_status).compact.sort
84 map(&:new_status).compact.sort
84 else
85 else
85 []
86 []
@@ -24,6 +24,7 class Journal < ActiveRecord::Base
24 belongs_to :user
24 belongs_to :user
25 has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
25 has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
26 attr_accessor :indice
26 attr_accessor :indice
27 attr_protected :id
27
28
28 acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" },
29 acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" },
29 :description => :notes,
30 :description => :notes,
@@ -34,17 +35,18 class Journal < ActiveRecord::Base
34
35
35 acts_as_activity_provider :type => 'issues',
36 acts_as_activity_provider :type => 'issues',
36 :author_key => :user_id,
37 :author_key => :user_id,
37 :find_options => {:include => [{:issue => :project}, :details, :user],
38 :scope => preload({:issue => :project}, :user).
38 :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
39 joins("LEFT OUTER JOIN #{JournalDetail.table_name} ON #{JournalDetail.table_name}.journal_id = #{Journal.table_name}.id").
39 " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
40 where("#{Journal.table_name}.journalized_type = 'Issue' AND" +
41 " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')")
40
42
41 before_create :split_private_notes
43 before_create :split_private_notes
42 after_create :send_notification
44 after_create :send_notification
43
45
44 scope :visible, lambda {|*args|
46 scope :visible, lambda {|*args|
45 user = args.shift || User.current
47 user = args.shift || User.current
46
48 joins(:issue => :project).
47 includes(:issue => :project).
49 references(:project).
48 where(Issue.visible_condition(user, *args)).
50 where(Issue.visible_condition(user, *args)).
49 where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false)
51 where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false)
50 }
52 }
@@ -18,6 +18,7
18 class JournalDetail < ActiveRecord::Base
18 class JournalDetail < ActiveRecord::Base
19 belongs_to :journal
19 belongs_to :journal
20 before_save :normalize_values
20 before_save :normalize_values
21 attr_protected :id
21
22
22 def custom_field
23 def custom_field
23 if property == 'cf'
24 if property == 'cf'
@@ -42,7 +42,7 class MailHandler < ActionMailer::Base
42 @@handler_options[:no_notification] = (@@handler_options[:no_notification].to_s == '1')
42 @@handler_options[:no_notification] = (@@handler_options[:no_notification].to_s == '1')
43 @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1')
43 @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1')
44
44
45 email.force_encoding('ASCII-8BIT') if email.respond_to?(:force_encoding)
45 email.force_encoding('ASCII-8BIT')
46 super(email)
46 super(email)
47 end
47 end
48
48
@@ -417,7 +417,7 class MailHandler < ActionMailer::Base
417 end
417 end
418
418
419 parts.reject! do |part|
419 parts.reject! do |part|
420 part.header[:content_disposition].try(:disposition_type) == 'attachment'
420 part.attachment?
421 end
421 end
422
422
423 @plain_text_body = parts.map do |p|
423 @plain_text_body = parts.map do |p|
@@ -25,6 +25,7 class Member < ActiveRecord::Base
25 validates_presence_of :principal, :project
25 validates_presence_of :principal, :project
26 validates_uniqueness_of :user_id, :scope => :project_id
26 validates_uniqueness_of :user_id, :scope => :project_id
27 validate :validate_role
27 validate :validate_role
28 attr_protected :id
28
29
29 before_destroy :set_issue_category_nil
30 before_destroy :set_issue_category_nil
30
31
@@ -26,6 +26,7 class MemberRole < ActiveRecord::Base
26
26
27 validates_presence_of :role
27 validates_presence_of :role
28 validate :validate_role_member
28 validate :validate_role_member
29 attr_protected :id
29
30
30 def validate_role_member
31 def validate_role_member
31 errors.add :role_id, :invalid if role && !role.member?
32 errors.add :role_id, :invalid if role && !role.member?
@@ -22,9 +22,10 class Message < ActiveRecord::Base
22 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
22 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
23 acts_as_attachable
23 acts_as_attachable
24 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
24 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
25 attr_protected :id
25
26
26 acts_as_searchable :columns => ['subject', 'content'],
27 acts_as_searchable :columns => ['subject', 'content'],
27 :include => {:board => :project},
28 :scope => preload(:board => :project),
28 :project_key => "#{Board.table_name}.project_id",
29 :project_key => "#{Board.table_name}.project_id",
29 :date_column => "#{table_name}.created_on"
30 :date_column => "#{table_name}.created_on"
30 acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
31 acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
@@ -34,7 +35,7 class Message < ActiveRecord::Base
34 :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
35 :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
35 {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})}
36 {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})}
36
37
37 acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]},
38 acts_as_activity_provider :scope => preload({:board => :project}, :author),
38 :author_key => :author_id
39 :author_key => :author_id
39 acts_as_watchable
40 acts_as_watchable
40
41
@@ -48,7 +49,9 class Message < ActiveRecord::Base
48 after_create :send_notification
49 after_create :send_notification
49
50
50 scope :visible, lambda {|*args|
51 scope :visible, lambda {|*args|
51 includes(:board => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
52 joins(:board => :project).
53 references(:board => :project).
54 where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
52 }
55 }
53
56
54 safe_attributes 'subject', 'content'
57 safe_attributes 'subject', 'content'
@@ -19,16 +19,18 class News < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 belongs_to :project
20 belongs_to :project
21 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
22 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
22 has_many :comments, lambda {order("created_on")}, :as => :commented, :dependent => :delete_all
23
23
24 validates_presence_of :title, :description
24 validates_presence_of :title, :description
25 validates_length_of :title, :maximum => 60
25 validates_length_of :title, :maximum => 60
26 validates_length_of :summary, :maximum => 255
26 validates_length_of :summary, :maximum => 255
27 attr_protected :id
27
28
28 acts_as_attachable :delete_permission => :manage_news
29 acts_as_attachable :delete_permission => :manage_news
29 acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
30 acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"],
31 :scope => preload(:project)
30 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
32 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
31 acts_as_activity_provider :find_options => {:include => [:project, :author]},
33 acts_as_activity_provider :scope => preload(:project, :author),
32 :author_key => :author_id
34 :author_key => :author_id
33 acts_as_watchable
35 acts_as_watchable
34
36
@@ -36,7 +38,9 class News < ActiveRecord::Base
36 after_create :send_notification
38 after_create :send_notification
37
39
38 scope :visible, lambda {|*args|
40 scope :visible, lambda {|*args|
39 includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
41 joins(:project).
42 references([:author, :project]).
43 where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
40 }
44 }
41
45
42 safe_attributes 'title', 'summary', 'description'
46 safe_attributes 'title', 'summary', 'description'
@@ -68,7 +72,7 class News < ActiveRecord::Base
68
72
69 # returns latest news for projects visible by user
73 # returns latest news for projects visible by user
70 def self.latest(user = User.current, count = 5)
74 def self.latest(user = User.current, count = 5)
71 visible(user).includes([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).all
75 visible(user).joins([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).to_a
72 end
76 end
73
77
74 private
78 private
@@ -25,11 +25,13 class Principal < ActiveRecord::Base
25 STATUS_LOCKED = 3
25 STATUS_LOCKED = 3
26
26
27 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
27 has_many :members, :foreign_key => 'user_id', :dependent => :destroy
28 has_many :memberships, :class_name => 'Member',
28 has_many :memberships,
29 :foreign_key => 'user_id',
29 lambda {preload(:project, :roles).
30 :include => [:project, :roles],
30 joins(:project).
31 :conditions => "#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}",
31 where("#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}").
32 :order => "#{Project.table_name}.name"
32 order("#{Project.table_name}.name")},
33 :class_name => 'Member',
34 :foreign_key => 'user_id'
33 has_many :projects, :through => :memberships
35 has_many :projects, :through => :memberships
34 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
36 has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
35
37
@@ -56,8 +58,8 class Principal < ActiveRecord::Base
56
58
57 # Principals that are members of a collection of projects
59 # Principals that are members of a collection of projects
58 scope :member_of, lambda {|projects|
60 scope :member_of, lambda {|projects|
59 projects = [projects] unless projects.is_a?(Array)
61 projects = [projects] if projects.is_a?(Project)
60 if projects.empty?
62 if projects.blank?
61 where("1=0")
63 where("1=0")
62 else
64 else
63 ids = projects.map(&:id)
65 ids = projects.map(&:id)
@@ -28,31 +28,35 class Project < ActiveRecord::Base
28
28
29 # Specific overridden Activities
29 # Specific overridden Activities
30 has_many :time_entry_activities
30 has_many :time_entry_activities
31 has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
31 has_many :members,
32 lambda { joins(:principal, :roles).
33 references(:principal, :roles).
34 where("#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}") }
32 has_many :memberships, :class_name => 'Member'
35 has_many :memberships, :class_name => 'Member'
33 has_many :member_principals, :class_name => 'Member',
36 has_many :member_principals,
34 :include => :principal,
37 lambda { joins(:principal).
35 :conditions => "#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
38 references(:principal).
36
39 where("#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}")},
40 :class_name => 'Member'
37 has_many :enabled_modules, :dependent => :delete_all
41 has_many :enabled_modules, :dependent => :delete_all
38 has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
42 has_and_belongs_to_many :trackers, lambda {order("#{Tracker.table_name}.position")}
39 has_many :issues, :dependent => :destroy, :include => [:status, :tracker]
43 has_many :issues, :dependent => :destroy
40 has_many :issue_changes, :through => :issues, :source => :journals
44 has_many :issue_changes, :through => :issues, :source => :journals
41 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
45 has_many :versions, lambda {order("#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC")}, :dependent => :destroy
42 has_many :time_entries, :dependent => :destroy
46 has_many :time_entries, :dependent => :destroy
43 has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all
47 has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all
44 has_many :documents, :dependent => :destroy
48 has_many :documents, :dependent => :destroy
45 has_many :news, :dependent => :destroy, :include => :author
49 has_many :news, lambda {includes(:author)}, :dependent => :destroy
46 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
50 has_many :issue_categories, lambda {order("#{IssueCategory.table_name}.name")}, :dependent => :delete_all
47 has_many :boards, :dependent => :destroy, :order => "position ASC"
51 has_many :boards, lambda {order("position ASC")}, :dependent => :destroy
48 has_one :repository, :conditions => ["is_default = ?", true]
52 has_one :repository, lambda {where(["is_default = ?", true])}
49 has_many :repositories, :dependent => :destroy
53 has_many :repositories, :dependent => :destroy
50 has_many :changesets, :through => :repository
54 has_many :changesets, :through => :repository
51 has_one :wiki, :dependent => :destroy
55 has_one :wiki, :dependent => :destroy
52 # Custom field for the project issues
56 # Custom field for the project issues
53 has_and_belongs_to_many :issue_custom_fields,
57 has_and_belongs_to_many :issue_custom_fields,
58 lambda {order("#{CustomField.table_name}.position")},
54 :class_name => 'IssueCustomField',
59 :class_name => 'IssueCustomField',
55 :order => "#{CustomField.table_name}.position",
56 :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
60 :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
57 :association_foreign_key => 'custom_field_id'
61 :association_foreign_key => 'custom_field_id'
58
62
@@ -126,9 +130,9 class Project < ActiveRecord::Base
126 if !initialized.key?('trackers') && !initialized.key?('tracker_ids')
130 if !initialized.key?('trackers') && !initialized.key?('tracker_ids')
127 default = Setting.default_projects_tracker_ids
131 default = Setting.default_projects_tracker_ids
128 if default.is_a?(Array)
132 if default.is_a?(Array)
129 self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.all
133 self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.to_a
130 else
134 else
131 self.trackers = Tracker.sorted.all
135 self.trackers = Tracker.sorted.to_a
132 end
136 end
133 end
137 end
134 end
138 end
@@ -144,7 +148,7 class Project < ActiveRecord::Base
144 # returns latest created projects
148 # returns latest created projects
145 # non public projects will be returned only if user is a member of those
149 # non public projects will be returned only if user is a member of those
146 def self.latest(user=nil, count=5)
150 def self.latest(user=nil, count=5)
147 visible(user).limit(count).order("created_on DESC").all
151 visible(user).limit(count).order("created_on DESC").to_a
148 end
152 end
149
153
150 # Returns true if the project is visible to +user+ or to the current user.
154 # Returns true if the project is visible to +user+ or to the current user.
@@ -212,9 +216,9 class Project < ActiveRecord::Base
212 end
216 end
213
217
214 def override_roles(role)
218 def override_roles(role)
215 @override_members ||= memberships.where(:user_id => [GroupAnonymous.instance_id, GroupNonMember.instance_id]).all
219 group_class = role.anonymous? ? GroupAnonymous : GroupNonMember
216 member = @override_members.detect {|m| role.anonymous? ^ (m.user_id == GroupNonMember.instance_id)}
220 member = member_principals.where("#{Principal.table_name}.type = ?", group_class.name).first
217 member ? member.roles : [role]
221 member ? member.roles.to_a : [role]
218 end
222 end
219
223
220 def principals
224 def principals
@@ -364,7 +368,7 class Project < ActiveRecord::Base
364 # by the current user
368 # by the current user
365 def allowed_parents
369 def allowed_parents
366 return @allowed_parents if @allowed_parents
370 return @allowed_parents if @allowed_parents
367 @allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).all
371 @allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).to_a
368 @allowed_parents = @allowed_parents - self_and_descendants
372 @allowed_parents = @allowed_parents - self_and_descendants
369 if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
373 if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
370 @allowed_parents << nil
374 @allowed_parents << nil
@@ -435,11 +439,12 class Project < ActiveRecord::Base
435 @rolled_up_trackers ||=
439 @rolled_up_trackers ||=
436 Tracker.
440 Tracker.
437 joins(:projects).
441 joins(:projects).
442 references(:project).
438 joins("JOIN #{EnabledModule.table_name} ON #{EnabledModule.table_name}.project_id = #{Project.table_name}.id AND #{EnabledModule.table_name}.name = 'issue_tracking'").
443 joins("JOIN #{EnabledModule.table_name} ON #{EnabledModule.table_name}.project_id = #{Project.table_name}.id AND #{EnabledModule.table_name}.name = 'issue_tracking'").
439 select("DISTINCT #{Tracker.table_name}.*").
444 select("DISTINCT #{Tracker.table_name}.*").
440 where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt).
445 where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt).
441 sorted.
446 sorted.
442 all
447 to_a
443 end
448 end
444
449
445 # Closes open and locked project versions that are completed
450 # Closes open and locked project versions that are completed
@@ -457,7 +462,8 class Project < ActiveRecord::Base
457 def rolled_up_versions
462 def rolled_up_versions
458 @rolled_up_versions ||=
463 @rolled_up_versions ||=
459 Version.
464 Version.
460 includes(:project).
465 joins(:project).
466 references(:project).
461 where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> ?", lft, rgt, STATUS_ARCHIVED)
467 where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> ?", lft, rgt, STATUS_ARCHIVED)
462 end
468 end
463
469
@@ -465,13 +471,17 class Project < ActiveRecord::Base
465 def shared_versions
471 def shared_versions
466 if new_record?
472 if new_record?
467 Version.
473 Version.
468 includes(:project).
474 joins(:project).
475 references(:project).
476 preload(:project).
469 where("#{Project.table_name}.status <> ? AND #{Version.table_name}.sharing = 'system'", STATUS_ARCHIVED)
477 where("#{Project.table_name}.status <> ? AND #{Version.table_name}.sharing = 'system'", STATUS_ARCHIVED)
470 else
478 else
471 @shared_versions ||= begin
479 @shared_versions ||= begin
472 r = root? ? self : root
480 r = root? ? self : root
473 Version.
481 Version.
474 includes(:project).
482 joins(:project).
483 references(:project).
484 preload(:project).
475 where("#{Project.table_name}.id = #{id}" +
485 where("#{Project.table_name}.id = #{id}" +
476 " OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
486 " OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
477 " #{Version.table_name}.sharing = 'system'" +
487 " #{Version.table_name}.sharing = 'system'" +
@@ -497,7 +507,7 class Project < ActiveRecord::Base
497 # Deletes all project's members
507 # Deletes all project's members
498 def delete_all_members
508 def delete_all_members
499 me, mr = Member.table_name, MemberRole.table_name
509 me, mr = Member.table_name, MemberRole.table_name
500 connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
510 self.class.connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
501 Member.delete_all(['project_id = ?', id])
511 Member.delete_all(['project_id = ?', id])
502 end
512 end
503
513
@@ -728,7 +738,7 class Project < ActiveRecord::Base
728 project = project.is_a?(Project) ? project : Project.find(project)
738 project = project.is_a?(Project) ? project : Project.find(project)
729
739
730 to_be_copied = %w(wiki versions issue_categories issues members queries boards)
740 to_be_copied = %w(wiki versions issue_categories issues members queries boards)
731 to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil?
741 to_be_copied = to_be_copied & Array.wrap(options[:only]) unless options[:only].nil?
732
742
733 Project.transaction do
743 Project.transaction do
734 if save
744 if save
@@ -740,6 +750,7 class Project < ActiveRecord::Base
740 save
750 save
741 end
751 end
742 end
752 end
753 true
743 end
754 end
744
755
745 # Returns a new unsaved Project instance with attributes copied from +project+
756 # Returns a new unsaved Project instance with attributes copied from +project+
@@ -958,11 +969,10 class Project < ActiveRecord::Base
958 def copy_queries(project)
969 def copy_queries(project)
959 project.queries.each do |query|
970 project.queries.each do |query|
960 new_query = IssueQuery.new
971 new_query = IssueQuery.new
961 new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria", "user_id", "type")
972 new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
962 new_query.sort_criteria = query.sort_criteria if query.sort_criteria
973 new_query.sort_criteria = query.sort_criteria if query.sort_criteria
963 new_query.project = self
974 new_query.project = self
964 new_query.user_id = query.user_id
975 new_query.user_id = query.user_id
965 new_query.role_ids = query.role_ids if query.visibility == IssueQuery::VISIBILITY_ROLES
966 self.queries << new_query
976 self.queries << new_query
967 end
977 end
968 end
978 end
@@ -288,7 +288,7 class Query < ActiveRecord::Base
288 end
288 end
289
289
290 def trackers
290 def trackers
291 @trackers ||= project.nil? ? Tracker.sorted.all : project.rolled_up_trackers
291 @trackers ||= project.nil? ? Tracker.sorted.to_a : project.rolled_up_trackers
292 end
292 end
293
293
294 # Returns a hash of localized labels for all filter operators
294 # Returns a hash of localized labels for all filter operators
@@ -306,7 +306,7 class Query < ActiveRecord::Base
306 end
306 end
307
307
308 def all_projects
308 def all_projects
309 @all_projects ||= Project.visible.all
309 @all_projects ||= Project.visible.to_a
310 end
310 end
311
311
312 def all_projects_values
312 def all_projects_values
@@ -655,7 +655,7 class Query < ActiveRecord::Base
655 sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}"
655 sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}"
656 end
656 end
657 else
657 else
658 sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
658 sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")"
659 end
659 end
660 else
660 else
661 # IN an empty set
661 # IN an empty set
@@ -663,7 +663,7 class Query < ActiveRecord::Base
663 end
663 end
664 when "!"
664 when "!"
665 if value.any?
665 if value.any?
666 sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
666 sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + "))"
667 else
667 else
668 # NOT IN an empty set
668 # NOT IN an empty set
669 sql = "1=1"
669 sql = "1=1"
@@ -705,9 +705,9 class Query < ActiveRecord::Base
705 end
705 end
706 end
706 end
707 when "o"
707 when "o"
708 sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id"
708 sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{self.class.connection.quoted_false})" if field == "status_id"
709 when "c"
709 when "c"
710 sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id"
710 sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{self.class.connection.quoted_true})" if field == "status_id"
711 when "><t-"
711 when "><t-"
712 # between today - n days and today
712 # between today - n days and today
713 sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
713 sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
@@ -769,9 +769,9 class Query < ActiveRecord::Base
769 date = Date.today
769 date = Date.today
770 sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year)
770 sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year)
771 when "~"
771 when "~"
772 sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
772 sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
773 when "!~"
773 when "!~"
774 sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
774 sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
775 else
775 else
776 raise "Unknown query operator #{operator}"
776 raise "Unknown query operator #{operator}"
777 end
777 end
@@ -834,7 +834,7 class Query < ActiveRecord::Base
834 if self.class.default_timezone == :utc
834 if self.class.default_timezone == :utc
835 from = from.utc
835 from = from.utc
836 end
836 end
837 s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from)])
837 s << ("#{table}.#{field} > '%s'" % [self.class.connection.quoted_date(from)])
838 end
838 end
839 if to
839 if to
840 if to.is_a?(Date)
840 if to.is_a?(Date)
@@ -843,7 +843,7 class Query < ActiveRecord::Base
843 if self.class.default_timezone == :utc
843 if self.class.default_timezone == :utc
844 to = to.utc
844 to = to.utc
845 end
845 end
846 s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to)])
846 s << ("#{table}.#{field} <= '%s'" % [self.class.connection.quoted_date(to)])
847 end
847 end
848 s.join(' AND ')
848 s.join(' AND ')
849 end
849 end
@@ -25,7 +25,7 class Repository < ActiveRecord::Base
25 IDENTIFIER_MAX_LENGTH = 255
25 IDENTIFIER_MAX_LENGTH = 255
26
26
27 belongs_to :project
27 belongs_to :project
28 has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
28 has_many :changesets, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
29 has_many :filechanges, :class_name => 'Change', :through => :changesets
30
30
31 serialize :extra_info
31 serialize :extra_info
@@ -45,6 +45,7 class Repository < ActiveRecord::Base
45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
45 validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
46 # Checks if the SCM is enabled when creating a repository
46 # Checks if the SCM is enabled when creating a repository
47 validate :repo_create_validation, :on => :create
47 validate :repo_create_validation, :on => :create
48 attr_protected :id
48
49
49 safe_attributes 'identifier',
50 safe_attributes 'identifier',
50 'login',
51 'login',
@@ -264,7 +265,7 class Repository < ActiveRecord::Base
264 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
265 reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
265 limit(limit).
266 limit(limit).
266 preload(:user).
267 preload(:user).
267 all
268 to_a
268 else
269 else
269 filechanges.
270 filechanges.
270 where("path = ?", path.with_leading_slash).
271 where("path = ?", path.with_leading_slash).
@@ -313,7 +314,8 class Repository < ActiveRecord::Base
313 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
314 return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
314
315
315 user = nil
316 user = nil
316 c = changesets.where(:committer => committer).includes(:user).first
317 c = changesets.where(:committer => committer).
318 includes(:user).references(:user).first
317 if c && c.user
319 if c && c.user
318 user = c.user
320 user = c.user
319 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
321 elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
@@ -484,10 +486,10 class Repository < ActiveRecord::Base
484 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
486 ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
485 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
487 cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
486
488
487 connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
489 self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
488 connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
490 self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
489 connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
491 self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
490 connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
492 self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
491 clear_extra_info_of_changesets
493 clear_extra_info_of_changesets
492 end
494 end
493
495
@@ -199,7 +199,7 class Repository::Cvs < Repository
199 # Need to retrieve existing revision numbers to sort them as integers
199 # Need to retrieve existing revision numbers to sort them as integers
200 sql = "SELECT revision FROM #{Changeset.table_name} "
200 sql = "SELECT revision FROM #{Changeset.table_name} "
201 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
201 sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
202 @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
202 @current_revision_number ||= (self.class.connection.select_values(sql).collect(&:to_i).max || 0)
203 @current_revision_number += 1
203 @current_revision_number += 1
204 end
204 end
205 end
205 end
@@ -241,7 +241,7 class Repository::Git < Repository
241 def latest_changesets(path,rev,limit=10)
241 def latest_changesets(path,rev,limit=10)
242 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
242 revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
243 return [] if revisions.nil? || revisions.empty?
243 return [] if revisions.nil? || revisions.empty?
244 changesets.where(:scmid => revisions.map {|c| c.scmid}).all
244 changesets.where(:scmid => revisions.map {|c| c.scmid}).to_a
245 end
245 end
246
246
247 def clear_extra_info_of_changesets
247 def clear_extra_info_of_changesets
@@ -20,7 +20,7 require 'redmine/scm/adapters/mercurial_adapter'
20 class Repository::Mercurial < Repository
20 class Repository::Mercurial < Repository
21 # sort changesets by revision number
21 # sort changesets by revision number
22 has_many :changesets,
22 has_many :changesets,
23 :order => "#{Changeset.table_name}.id DESC",
23 lambda {order("#{Changeset.table_name}.id DESC")},
24 :foreign_key => 'repository_id'
24 :foreign_key => 'repository_id'
25
25
26 attr_protected :root_url
26 attr_protected :root_url
@@ -117,9 +117,10 class Repository::Mercurial < Repository
117 changesets.
117 changesets.
118 includes(:user).
118 includes(:user).
119 where(latest_changesets_cond(path, rev, limit)).
119 where(latest_changesets_cond(path, rev, limit)).
120 references(:user).
120 limit(limit).
121 limit(limit).
121 order("#{Changeset.table_name}.id DESC").
122 order("#{Changeset.table_name}.id DESC").
122 all
123 to_a
123 end
124 end
124
125
125 def is_short_id_in_db?
126 def is_short_id_in_db?
@@ -42,7 +42,7 class Repository::Subversion < Repository
42 revisions = scm.revisions(path, rev, nil, :limit => limit)
42 revisions = scm.revisions(path, rev, nil, :limit => limit)
43 if revisions
43 if revisions
44 identifiers = revisions.collect(&:identifier).compact
44 identifiers = revisions.collect(&:identifier).compact
45 changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).all
45 changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).to_a
46 else
46 else
47 []
47 []
48 end
48 end
@@ -166,7 +166,7 class Role < ActiveRecord::Base
166
166
167 # Find all the roles that can be given to a project member
167 # Find all the roles that can be given to a project member
168 def self.find_all_givable
168 def self.find_all_givable
169 Role.givable.all
169 Role.givable.to_a
170 end
170 end
171
171
172 # Return the builtin 'non member' role. If the role doesn't exist,
172 # Return the builtin 'non member' role. If the role doesn't exist,
@@ -86,6 +86,7 class Setting < ActiveRecord::Base
86 validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
86 validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
87 (s = @@available_settings[setting.name]) && s['format'] == 'int'
87 (s = @@available_settings[setting.name]) && s['format'] == 'int'
88 }
88 }
89 attr_protected :id
89
90
90 # Hash used to cache setting values
91 # Hash used to cache setting values
91 @cached_settings = {}
92 @cached_settings = {}
@@ -142,6 +143,7 END_SRC
142 def self.set_from_params(name, params)
143 def self.set_from_params(name, params)
143 params = params.dup
144 params = params.dup
144 params.delete_if {|v| v.blank? } if params.is_a?(Array)
145 params.delete_if {|v| v.blank? } if params.is_a?(Array)
146 params.symbolize_keys! if params.is_a?(Hash)
145
147
146 m = "#{name}_from_params"
148 m = "#{name}_from_params"
147 if respond_to? m
149 if respond_to? m
@@ -35,7 +35,7 class TimeEntry < ActiveRecord::Base
35
35
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
36 acts_as_activity_provider :timestamp => "#{table_name}.created_on",
37 :author_key => :user_id,
37 :author_key => :user_id,
38 :find_options => {:include => :project}
38 :scope => preload(:project)
39
39
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
40 validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
41 validates_numericality_of :hours, :allow_nil => true, :message => :invalid
@@ -45,13 +45,19 class TimeEntry < ActiveRecord::Base
45 validate :validate_time_entry
45 validate :validate_time_entry
46
46
47 scope :visible, lambda {|*args|
47 scope :visible, lambda {|*args|
48 includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
48 joins(:project).
49 references(:project).
50 where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
49 }
51 }
50 scope :on_issue, lambda {|issue|
52 scope :on_issue, lambda {|issue|
51 includes(:issue).where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
53 joins(:issue).
54 references(:issue).
55 where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
52 }
56 }
53 scope :on_project, lambda {|project, include_subprojects|
57 scope :on_project, lambda {|project, include_subprojects|
54 includes(:project).where(project.project_condition(include_subprojects))
58 joins(:project).
59 references(:project).
60 where(project.project_condition(include_subprojects))
55 }
61 }
56 scope :spent_between, lambda {|from, to|
62 scope :spent_between, lambda {|from, to|
57 if from && to
63 if from && to
@@ -42,7 +42,7 class TimeEntryQuery < Query
42 if project
42 if project
43 principals += project.principals.sort
43 principals += project.principals.sort
44 unless project.leaf?
44 unless project.leaf?
45 subprojects = project.descendants.visible.all
45 subprojects = project.descendants.visible.to_a
46 if subprojects.any?
46 if subprojects.any?
47 add_available_filter "subproject_id",
47 add_available_filter "subproject_id",
48 :type => :list_subprojects,
48 :type => :list_subprojects,
@@ -109,7 +109,8 class TimeEntryQuery < Query
109 where(statement).
109 where(statement).
110 order(order_option).
110 order(order_option).
111 joins(joins_for_order_statement(order_option.join(','))).
111 joins(joins_for_order_statement(order_option.join(','))).
112 includes(:activity)
112 includes(:activity).
113 references(:activity)
113 end
114 end
114
115
115 def sql_for_activity_id_field(field, operator, value)
116 def sql_for_activity_id_field(field, operator, value)
@@ -18,6 +18,7
18 class Token < ActiveRecord::Base
18 class Token < ActiveRecord::Base
19 belongs_to :user
19 belongs_to :user
20 validates_uniqueness_of :value
20 validates_uniqueness_of :value
21 attr_protected :id
21
22
22 before_create :delete_previous_tokens, :generate_new_token
23 before_create :delete_previous_tokens, :generate_new_token
23
24
@@ -63,7 +63,7 class Tracker < ActiveRecord::Base
63 connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE tracker_id = #{id} AND type = 'WorkflowTransition'").
63 connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE tracker_id = #{id} AND type = 'WorkflowTransition'").
64 flatten.
64 flatten.
65 uniq
65 uniq
66 @issue_statuses = IssueStatus.where(:id => ids).all.sort
66 @issue_statuses = IssueStatus.where(:id => ids).to_a.sort
67 end
67 end
68
68
69 def disabled_core_fields
69 def disabled_core_fields
@@ -92,7 +92,7 class Tracker < ActiveRecord::Base
92 # Returns the fields that are disabled for all the given trackers
92 # Returns the fields that are disabled for all the given trackers
93 def self.disabled_core_fields(trackers)
93 def self.disabled_core_fields(trackers)
94 if trackers.present?
94 if trackers.present?
95 trackers.uniq.map(&:disabled_core_fields).reduce(:&)
95 trackers.map(&:disabled_core_fields).reduce(:&)
96 else
96 else
97 []
97 []
98 end
98 end
@@ -79,8 +79,8 class User < Principal
79 :after_remove => Proc.new {|user, group| group.user_removed(user)}
79 :after_remove => Proc.new {|user, group| group.user_removed(user)}
80 has_many :changesets, :dependent => :nullify
80 has_many :changesets, :dependent => :nullify
81 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
81 has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
82 has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
82 has_one :rss_token, lambda {where "action='feeds'"}, :class_name => 'Token'
83 has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
83 has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token'
84 belongs_to :auth_source
84 belongs_to :auth_source
85
85
86 scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
86 scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
@@ -105,9 +105,13 class User < Principal
105 validates_length_of :firstname, :lastname, :maximum => 30
105 validates_length_of :firstname, :lastname, :maximum => 30
106 validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
106 validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
107 validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
107 validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
108 validates_confirmation_of :password, :allow_nil => true
109 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
108 validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
110 validate :validate_password_length
109 validate :validate_password_length
110 validate do
111 if password_confirmation && password != password_confirmation
112 errors.add(:password, :confirmation)
113 end
114 end
111
115
112 before_create :set_mail_notification
116 before_create :set_mail_notification
113 before_save :generate_password_if_needed, :update_hashed_password
117 before_save :generate_password_if_needed, :update_hashed_password
@@ -151,6 +155,15 class User < Principal
151 write_attribute(:mail, arg.to_s.strip)
155 write_attribute(:mail, arg.to_s.strip)
152 end
156 end
153
157
158 def self.find_or_initialize_by_identity_url(url)
159 user = where(:identity_url => url).first
160 unless user
161 user = User.new
162 user.identity_url = url
163 end
164 user
165 end
166
154 def identity_url=(url)
167 def identity_url=(url)
155 if url.blank?
168 if url.blank?
156 write_attribute(:identity_url, '')
169 write_attribute(:identity_url, '')
@@ -496,10 +509,12 class User < Principal
496
509
497 hash = Hash.new([])
510 hash = Hash.new([])
498
511
499 members = Member.joins(:project).
512 group_class = anonymous? ? GroupAnonymous : GroupNonMember
513 members = Member.joins(:project, :principal).
500 where("#{Project.table_name}.status <> 9").
514 where("#{Project.table_name}.status <> 9").
501 where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Member.table_name}.user_id = ?)", self.id, true, Group.builtin_id(self)).
515 where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Principal.table_name}.type = ?)", self.id, true, group_class.name).
502 preload(:project, :roles)
516 preload(:project, :roles).
517 to_a
503
518
504 members.reject! {|member| member.user_id != id && project_ids.include?(member.project_id)}
519 members.reject! {|member| member.user_id != id && project_ids.include?(member.project_id)}
505 members.each do |member|
520 members.each do |member|
@@ -558,6 +573,8 class User < Principal
558 # Authorize if user is authorized on every element of the array
573 # Authorize if user is authorized on every element of the array
559 context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
574 context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
560 end
575 end
576 elsif context
577 raise ArgumentError.new("#allowed_to? context argument must be a Project, an Array of projects or nil")
561 elsif options[:global]
578 elsif options[:global]
562 # Admin users are always authorized
579 # Admin users are always authorized
563 return true if admin?
580 return true if admin?
@@ -33,11 +33,14 class Version < ActiveRecord::Base
33 validates :effective_date, :date => true
33 validates :effective_date, :date => true
34 validates_inclusion_of :status, :in => VERSION_STATUSES
34 validates_inclusion_of :status, :in => VERSION_STATUSES
35 validates_inclusion_of :sharing, :in => VERSION_SHARINGS
35 validates_inclusion_of :sharing, :in => VERSION_SHARINGS
36 attr_protected :id
36
37
37 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
38 scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
38 scope :open, lambda { where(:status => 'open') }
39 scope :open, lambda { where(:status => 'open') }
39 scope :visible, lambda {|*args|
40 scope :visible, lambda {|*args|
40 includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues))
41 joins(:project).
42 references(:project).
43 where(Project.allowed_to_condition(args.first || User.current, :view_issues))
41 }
44 }
42
45
43 safe_attributes 'name',
46 safe_attributes 'name',
@@ -230,11 +233,6 class Version < ActiveRecord::Base
230 end
233 end
231 end
234 end
232
235
233 # Returns true if the version is shared, otherwise false
234 def shared?
235 sharing != 'none'
236 end
237
238 private
236 private
239
237
240 def load_issue_counts
238 def load_issue_counts
@@ -22,6 +22,7 class Watcher < ActiveRecord::Base
22 validates_presence_of :user
22 validates_presence_of :user
23 validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
23 validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
24 validate :validate_user
24 validate :validate_user
25 attr_protected :id
25
26
26 # Returns true if at least one object among objects is watched by user
27 # Returns true if at least one object among objects is watched by user
27 def self.any_watched?(objects, user)
28 def self.any_watched?(objects, user)
@@ -18,13 +18,14
18 class Wiki < ActiveRecord::Base
18 class Wiki < ActiveRecord::Base
19 include Redmine::SafeAttributes
19 include Redmine::SafeAttributes
20 belongs_to :project
20 belongs_to :project
21 has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
21 has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
22 has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
22 has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
23
23
24 acts_as_watchable
24 acts_as_watchable
25
25
26 validates_presence_of :start_page
26 validates_presence_of :start_page
27 validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
27 validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
28 attr_protected :id
28
29
29 safe_attributes 'start_page'
30 safe_attributes 'start_page'
30
31
@@ -23,6 +23,7 class WikiContent < ActiveRecord::Base
23 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
23 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
24 validates_presence_of :text
24 validates_presence_of :text
25 validates_length_of :comments, :maximum => 255, :allow_nil => true
25 validates_length_of :comments, :maximum => 255, :allow_nil => true
26 attr_protected :id
26
27
27 acts_as_versioned
28 acts_as_versioned
28
29
@@ -68,13 +69,13 class WikiContent < ActiveRecord::Base
68 :timestamp => "#{WikiContent.versioned_table_name}.updated_on",
69 :timestamp => "#{WikiContent.versioned_table_name}.updated_on",
69 :author_key => "#{WikiContent.versioned_table_name}.author_id",
70 :author_key => "#{WikiContent.versioned_table_name}.author_id",
70 :permission => :view_wiki_edits,
71 :permission => :view_wiki_edits,
71 :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
72 :scope => select("#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
72 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
73 "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
73 "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
74 "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
74 "#{WikiContent.versioned_table_name}.id",
75 "#{WikiContent.versioned_table_name}.id").
75 :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
76 joins("LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
76 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
77 "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
77 "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
78 "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id")
78
79
79 after_destroy :page_update_after_destroy
80 after_destroy :page_update_after_destroy
80
81
@@ -104,7 +105,7 class WikiContent < ActiveRecord::Base
104 # uncompressed data
105 # uncompressed data
105 data
106 data
106 end
107 end
107 str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
108 str.force_encoding("UTF-8")
108 str
109 str
109 end
110 end
110 end
111 end
@@ -33,7 +33,7 class WikiPage < ActiveRecord::Base
33 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
33 :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
34
34
35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
35 acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
36 :include => [{:wiki => :project}, :content],
36 :scope => preload(:wiki => :project).joins(:content, {:wiki => :project}),
37 :permission => :view_wiki_pages,
37 :permission => :view_wiki_pages,
38 :project_key => "#{Wiki.table_name}.project_id"
38 :project_key => "#{Wiki.table_name}.project_id"
39
39
@@ -43,6 +43,7 class WikiPage < ActiveRecord::Base
43 validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
43 validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
44 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
45 validates_associated :content
45 validates_associated :content
46 attr_protected :id
46
47
47 validate :validate_parent_title
48 validate :validate_parent_title
48 before_destroy :remove_redirects
49 before_destroy :remove_redirects
@@ -180,12 +181,10 class WikiPage < ActiveRecord::Base
180 def save_with_content(content)
181 def save_with_content(content)
181 ret = nil
182 ret = nil
182 transaction do
183 transaction do
183 self.content = content
184 if new_record?
185 # Rails automatically saves associated content
186 ret = save
184 ret = save
187 else
185 if content.text_changed?
188 ret = save && (content.text_changed? ? content.save : true)
186 self.content = content
187 ret = ret && content.changed?
189 end
188 end
190 raise ActiveRecord::Rollback unless ret
189 raise ActiveRecord::Rollback unless ret
191 end
190 end
@@ -20,4 +20,5 class WikiRedirect < ActiveRecord::Base
20
20
21 validates_presence_of :title, :redirects_to
21 validates_presence_of :title, :redirects_to
22 validates_length_of :title, :redirects_to, :maximum => 255
22 validates_length_of :title, :redirects_to, :maximum => 255
23 attr_protected :id
23 end
24 end
@@ -24,6 +24,7 class WorkflowRule < ActiveRecord::Base
24 belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
24 belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
25
25
26 validates_presence_of :role, :tracker, :old_status
26 validates_presence_of :role, :tracker, :old_status
27 attr_protected :id
27
28
28 # Copies workflows from source to targets
29 # Copies workflows from source to targets
29 def self.copy(source_tracker, source_role, target_trackers, target_roles)
30 def self.copy(source_tracker, source_role, target_trackers, target_roles)
@@ -34,7 +35,7 class WorkflowRule < ActiveRecord::Base
34 target_trackers = [target_trackers].flatten.compact
35 target_trackers = [target_trackers].flatten.compact
35 target_roles = [target_roles].flatten.compact
36 target_roles = [target_roles].flatten.compact
36
37
37 target_trackers = Tracker.sorted.all if target_trackers.empty?
38 target_trackers = Tracker.sorted.to_a if target_trackers.empty?
38 target_roles = Role.all if target_roles.empty?
39 target_roles = Role.all if target_roles.empty?
39
40
40 target_trackers.each do |target_tracker|
41 target_trackers.each do |target_tracker|
@@ -40,7 +40,7 class WorkflowTransition < WorkflowRule
40 roles = Array.wrap roles
40 roles = Array.wrap roles
41
41
42 transaction do
42 transaction do
43 records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).all
43 records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).to_a
44
44
45 transitions.each do |old_status_id, transitions_by_new_status|
45 transitions.each do |old_status_id, transitions_by_new_status|
46 transitions_by_new_status.each do |new_status_id, transition_by_rule|
46 transitions_by_new_status.each do |new_status_id, transition_by_rule|
@@ -8,8 +8,8
8 <% end -%>
8 <% end -%>
9 </ul>
9 </ul>
10 <div class="tabs-buttons" style="display:none;">
10 <div class="tabs-buttons" style="display:none;">
11 <button class="tab-left" type="button" onclick="moveTabLeft(this);"></button>
11 <button class="tab-left" onclick="moveTabLeft(this); return false;"></button>
12 <button class="tab-right" type="button" onclick="moveTabRight(this);"></button>
12 <button class="tab-right" onclick="moveTabRight(this); return false;"></button>
13 </div>
13 </div>
14 </div>
14 </div>
15
15
@@ -1,5 +1,5
1 <% roles = Role.find_all_givable %>
1 <% roles = Role.find_all_givable %>
2 <% projects = Project.active.all %>
2 <% projects = Project.active.to_a %>
3
3
4 <div class="splitcontentleft">
4 <div class="splitcontentleft">
5 <% if @group.memberships.any? %>
5 <% if @group.memberships.any? %>
@@ -1,6 +1,6
1 <%= error_messages_for 'member' %>
1 <%= error_messages_for 'member' %>
2 <% roles = Role.find_all_givable
2 <% roles = Role.find_all_givable
3 members = @project.member_principals.includes(:member_roles, :roles, :principal).all.sort %>
3 members = @project.member_principals.includes(:member_roles, :roles, :principal).to_a.sort %>
4
4
5 <div class="splitcontentleft">
5 <div class="splitcontentleft">
6 <% if members.any? %>
6 <% if members.any? %>
@@ -8,7 +8,7
8 <% elsif params[:issue_id] %>
8 <% elsif params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
9 <%= hidden_field_tag 'issue_id', params[:issue_id] %>
10 <% else %>
10 <% else %>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).all, :selected => @time_entry.project, :include_blank => true) %></p>
11 <p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).to_a, :selected => @time_entry.project, :include_blank => true) %></p>
12 <% end %>
12 <% end %>
13 <% end %>
13 <% end %>
14 <p>
14 <p>
@@ -1,5 +1,5
1 <% roles = Role.find_all_givable %>
1 <% roles = Role.find_all_givable %>
2 <% projects = Project.active.all %>
2 <% projects = Project.active.to_a %>
3
3
4 <div class="splitcontentleft">
4 <div class="splitcontentleft">
5 <% if @user.memberships.any? %>
5 <% if @user.memberships.any? %>
@@ -23,7 +23,7
23 <%= fp.select :parent_id,
23 <%= fp.select :parent_id,
24 content_tag('option', '', :value => '') +
24 content_tag('option', '', :value => '') +
25 wiki_page_options_for_select(
25 wiki_page_options_for_select(
26 @wiki.pages.includes(:parent).all -
26 @wiki.pages.includes(:parent).to_a -
27 @page.self_and_descendants, @page.parent) %>
27 @page.self_and_descendants, @page.parent) %>
28 </p>
28 </p>
29 <% end %>
29 <% end %>
@@ -13,7 +13,7
13 <p><%= f.select :parent_id,
13 <p><%= f.select :parent_id,
14 content_tag('option', '', :value => '') +
14 content_tag('option', '', :value => '') +
15 wiki_page_options_for_select(
15 wiki_page_options_for_select(
16 @wiki.pages.includes(:parent).all - @page.self_and_descendants,
16 @wiki.pages.includes(:parent).to_a - @page.self_and_descendants,
17 @page.parent),
17 @page.parent),
18 :label => :field_parent_title %></p>
18 :label => :field_parent_title %></p>
19 </div>
19 </div>
@@ -2,12 +2,7 require File.expand_path('../boot', __FILE__)
2
2
3 require 'rails/all'
3 require 'rails/all'
4
4
5 if defined?(Bundler)
5 Bundler.require(*Rails.groups)
6 # If you precompile assets before deploying to production, use this line
7 Bundler.require(*Rails.groups(:assets => %w(development test)))
8 # If you want your assets lazily compiled in production, use this line
9 # Bundler.require(:default, :assets, Rails.env)
10 end
11
6
12 module RedmineApp
7 module RedmineApp
13 class Application < Rails::Application
8 class Application < Rails::Application
@@ -33,7 +28,7 module RedmineApp
33 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
28 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
34 # config.i18n.default_locale = :de
29 # config.i18n.default_locale = :de
35
30
36 I18n.enforce_available_locales = false
31 I18n.enforce_available_locales = true
37
32
38 # Configure the default encoding used in templates for Ruby 1.9.
33 # Configure the default encoding used in templates for Ruby 1.9.
39 config.encoding = "utf-8"
34 config.encoding = "utf-8"
@@ -1,5 +1,3
1 require 'rubygems'
2
3 # Set up gems listed in the Gemfile.
1 # Set up gems listed in the Gemfile.
4 ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
2 ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
5
3
@@ -1,5 +1,4
1 # Default setup is given for MySQL with ruby1.9. If you're running Redmine
1 # Default setup is given for MySQL with ruby1.9.
2 # with MySQL and ruby1.8, replace the adapter name with `mysql`.
3 # Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end.
2 # Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end.
4 # Line indentation must be 2 spaces (no tabs).
3 # Line indentation must be 2 spaces (no tabs).
5
4
@@ -1,4 +1,4
1 # Load the rails application
1 # Load the Rails application
2 require File.expand_path('../application', __FILE__)
2 require File.expand_path('../application', __FILE__)
3
3
4 # Make sure there's no plugin in vendor/plugin before starting
4 # Make sure there's no plugin in vendor/plugin before starting
@@ -10,5 +10,5 if Dir.glob(File.join(vendor_plugins_dir, "*")).any?
10 exit 1
10 exit 1
11 end
11 end
12
12
13 # Initialize the rails application
13 # Initialize the Rails application
14 RedmineApp::Application.initialize!
14 Rails.application.initialize!
@@ -1,19 +1,21
1 Rails.application.configure do
1 # Settings specified here will take precedence over those in config/application.rb
2 # Settings specified here will take precedence over those in config/application.rb
2 RedmineApp::Application.configure do
3
3 # In the development environment your application's code is reloaded on
4 # In the development environment your application's code is reloaded on
4 # every request. This slows down response time but is perfect for development
5 # every request. This slows down response time but is perfect for development
5 # since you don't have to restart the webserver when you make code changes.
6 # since you don't have to restart the webserver when you make code changes.
6 config.cache_classes = false
7 config.cache_classes = false
7
8
8 # Log error messages when you accidentally call methods on nil.
9 # Do not eager load code on boot.
9 config.whiny_nils = true
10 config.eager_load = false
10
11
11 # Show full error reports and disable caching
12 # Show full error reports and disable caching
12 #config.action_controller.consider_all_requests_local = true
13 config.consider_all_requests_local = true
13 config.action_controller.perform_caching = false
14 config.action_controller.perform_caching = false
14
15
15 # Don't care if the mailer can't send
16 # Disable delivery errors
16 config.action_mailer.raise_delivery_errors = false
17 config.action_mailer.raise_delivery_errors = false
17
18
19 # Print deprecation notices to stderr and the Rails logger.
18 config.active_support.deprecation = [:stderr, :log]
20 config.active_support.deprecation = [:stderr, :log]
19 end
21 end
@@ -1,33 +1,25
1 Rails.application.configure do
1 # Settings specified here will take precedence over those in config/application.rb
2 # Settings specified here will take precedence over those in config/application.rb
2 RedmineApp::Application.configure do
3
3 # The production environment is meant for finished, "live" apps.
4 # Code is not reloaded between requests.
4 # Code is not reloaded between requests
5 config.cache_classes = true
5 config.cache_classes = true
6
6
7 #####
7 # Eager load code on boot. This eager loads most of Rails and
8 # Customize the default logger
8 # your application in memory, allowing both threaded web servers
9 # http://www.ruby-doc.org/stdlib-1.8.7/libdoc/logger/rdoc/Logger.html
9 # and those relying on copy on write to perform better.
10 #
10 # Rake tasks automatically ignore this option for performance.
11 # Use a different logger for distributed setups
11 config.eager_load = true
12 # config.logger = SyslogLogger.new
13 #
14 # Rotate logs bigger than 1MB, keeps no more than 7 rotated logs around.
15 # When setting a new Logger, make sure to set it's log level too.
16 #
17 # config.logger = Logger.new(config.log_path, 7, 1048576)
18 # config.logger.level = Logger::INFO
19
12
20 # Full error reports are disabled and caching is turned on
13 # Full error reports are disabled and caching is turned on.
14 config.consider_all_requests_local = false
21 config.action_controller.perform_caching = true
15 config.action_controller.perform_caching = true
22
16
23 # Enable serving of images, stylesheets, and javascripts from an asset server
17 # Disable delivery errors
24 # config.action_controller.asset_host = "http://assets.example.com"
25
26 # Disable delivery errors if you bad email addresses should just be ignored
27 config.action_mailer.raise_delivery_errors = false
18 config.action_mailer.raise_delivery_errors = false
28
19
29 # No email in production log
20 # No email in production log
30 config.action_mailer.logger = nil
21 config.action_mailer.logger = nil
31
22
23 # Print deprecation notices to the Rails logger.
32 config.active_support.deprecation = :log
24 config.active_support.deprecation = :log
33 end
25 end
@@ -1,16 +1,19
1 Rails.application.configure do
1 # Settings specified here will take precedence over those in config/application.rb
2 # Settings specified here will take precedence over those in config/application.rb
2 RedmineApp::Application.configure do
3
3 # The test environment is used exclusively to run your application's
4 # The test environment is used exclusively to run your application's
4 # test suite. You never need to work with it otherwise. Remember that
5 # test suite. You never need to work with it otherwise. Remember that
5 # your test database is "scratch space" for the test suite and is wiped
6 # your test database is "scratch space" for the test suite and is wiped
6 # and recreated between test runs. Don't rely on the data there!
7 # and recreated between test runs. Don't rely on the data there!
7 config.cache_classes = true
8 config.cache_classes = true
8
9
9 # Log error messages when you accidentally call methods on nil.
10 # Do not eager load code on boot. This avoids loading your whole application
10 config.whiny_nils = true
11 # just for the purpose of running a single test. If you are using a tool that
12 # preloads Rails for running tests, you may have to set it to true.
13 config.eager_load = false
11
14
12 # Show full error reports and disable caching
15 # Show full error reports and disable caching
13 #config.action_controller.consider_all_requests_local = true
16 config.consider_all_requests_local = true
14 config.action_controller.perform_caching = false
17 config.action_controller.perform_caching = false
15
18
16 config.action_mailer.perform_deliveries = true
19 config.action_mailer.perform_deliveries = true
@@ -20,10 +23,10 RedmineApp::Application.configure do
20 # ActionMailer::Base.deliveries array.
23 # ActionMailer::Base.deliveries array.
21 config.action_mailer.delivery_method = :test
24 config.action_mailer.delivery_method = :test
22
25
23 # Skip protect_from_forgery in requests
26 # Disable request forgery protection in test environment.
24 # http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application
25 config.action_controller.allow_forgery_protection = false
27 config.action_controller.allow_forgery_protection = false
26
28
29 # Print deprecation notices to stderr and the Rails logger.
27 config.active_support.deprecation = [:stderr, :log]
30 config.active_support.deprecation = [:stderr, :log]
28
31
29 config.secret_token = 'a secret token for running the tests'
32 config.secret_token = 'a secret token for running the tests'
@@ -1,1 +1,2
1 # Same as test.rb
1 instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
2 instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
@@ -1,1 +1,2
1 # Same as test.rb
1 instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
2 instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
@@ -54,47 +54,13 module ActionView
54 end
54 end
55 end
55 end
56
56
57 # Do not HTML escape text templates
58 module ActionView
59 class Template
60 module Handlers
61 class ERB
62 def call(template)
63 if template.source.encoding_aware?
64 # First, convert to BINARY, so in case the encoding is
65 # wrong, we can still find an encoding tag
66 # (<%# encoding %>) inside the String using a regular
67 # expression
68 template_source = template.source.dup.force_encoding("BINARY")
69
70 erb = template_source.gsub(ENCODING_TAG, '')
71 encoding = $2
72
73 erb.force_encoding valid_encoding(template.source.dup, encoding)
74
75 # Always make sure we return a String in the default_internal
76 erb.encode!
77 else
78 erb = template.source.dup
79 end
80
81 self.class.erb_implementation.new(
82 erb,
83 :trim => (self.class.erb_trim_mode == "-"),
84 :escape => template.identifier =~ /\.text/ # only escape HTML templates
85 ).src
86 end
87 end
88 end
89 end
90 end
91
92 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe }
57 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe }
93
58
94 # HTML5: <option value=""></option> is invalid, use <option value="">&nbsp;</option> instead
59 # HTML5: <option value=""></option> is invalid, use <option value="">&nbsp;</option> instead
95 module ActionView
60 module ActionView
96 module Helpers
61 module Helpers
97 class InstanceTag
62 module Tags
63 class Base
98 private
64 private
99 def add_options_with_non_empty_blank_option(option_tags, options, value = nil)
65 def add_options_with_non_empty_blank_option(option_tags, options, value = nil)
100 if options[:include_blank] == true
66 if options[:include_blank] == true
@@ -105,6 +71,7 module ActionView
105 end
71 end
106 alias_method_chain :add_options, :non_empty_blank_option
72 alias_method_chain :add_options, :non_empty_blank_option
107 end
73 end
74 end
108
75
109 module FormTagHelper
76 module FormTagHelper
110 def select_tag_with_non_empty_blank_option(name, option_tags = nil, options = {})
77 def select_tag_with_non_empty_blank_option(name, option_tags = nil, options = {})
@@ -1,5 +1,7
1 I18n.default_locale = 'en'
1 I18n.default_locale = 'en'
2 I18n.backend = Redmine::I18n::Backend.new
2 I18n.backend = Redmine::I18n::Backend.new
3 # Forces I18n to load available locales from the backend
4 I18n.config.available_locales = nil
3
5
4 require 'redmine'
6 require 'redmine'
5
7
@@ -20,9 +22,3 Redmine::Plugin.load
20 unless Redmine::Configuration['mirror_plugins_assets_on_startup'] == false
22 unless Redmine::Configuration['mirror_plugins_assets_on_startup'] == false
21 Redmine::Plugin.mirror_assets
23 Redmine::Plugin.mirror_assets
22 end
24 end
23
24 Rails.application.config.to_prepare do
25 Redmine::FieldFormat::RecordList.subclasses.each do |klass|
26 klass.instance.reset_target_class
27 end
28 end No newline at end of file
@@ -249,8 +249,8 ja:
249 field_is_for_all: 全プロジェクト向け
249 field_is_for_all: 全プロジェクト向け
250 field_possible_values: 選択肢
250 field_possible_values: 選択肢
251 field_regexp: 正規表現
251 field_regexp: 正規表現
252 field_min_length: 短長
252 field_min_length: 小値
253 field_max_length: 最大
253 field_max_length: 最大
254 field_value:
254 field_value:
255 field_category: カテゴリ
255 field_category: カテゴリ
256 field_title: タイトル
256 field_title: タイトル
@@ -305,7 +305,7 ja:
305 field_activity: 活動
305 field_activity: 活動
306 field_spent_on: 日付
306 field_spent_on: 日付
307 field_identifier: 識別子
307 field_identifier: 識別子
308 field_is_filter: フィルタとして使
308 field_is_filter: フィルタとして使
309 field_issue_to: 関連するチケット
309 field_issue_to: 関連するチケット
310 field_delay: 遅延
310 field_delay: 遅延
311 field_assignable: このロールにチケットを割り当て可能
311 field_assignable: このロールにチケットを割り当て可能
@@ -314,7 +314,7 ja:
314 field_column_names: 項目
314 field_column_names: 項目
315 field_time_entries: 時間を記録
315 field_time_entries: 時間を記録
316 field_time_zone: タイムゾーン
316 field_time_zone: タイムゾーン
317 field_searchable: 検索対象
317 field_searchable: 検索条件に設定可能とする
318 field_default_value: デフォルト値
318 field_default_value: デフォルト値
319 field_comments_sorting: コメントの表示順
319 field_comments_sorting: コメントの表示順
320 field_parent_title: 親ページ
320 field_parent_title: 親ページ
@@ -541,7 +541,7 ja:
541 label_subproject_plural: サブプロジェクト
541 label_subproject_plural: サブプロジェクト
542 label_subproject_new: 新しいサブプロジェクト
542 label_subproject_new: 新しいサブプロジェクト
543 label_and_its_subprojects: "%{value} とサブプロジェクト"
543 label_and_its_subprojects: "%{value} とサブプロジェクト"
544 label_min_max_length: - 最大長
544 label_min_max_length: 小値 - 最大値の
545 label_list: リストから選択
545 label_list: リストから選択
546 label_date: 日付
546 label_date: 日付
547 label_integer: 整数
547 label_integer: 整数
@@ -997,7 +997,6
997 label_only: 僅於
997 label_only: 僅於
998 label_drop_down_list: 下拉式清單
998 label_drop_down_list: 下拉式清單
999 label_checkboxes: 核取方塊
999 label_checkboxes: 核取方塊
1000 label_radio_buttons: 選項按鈕
1001 label_link_values_to: 連結欄位值至此網址
1000 label_link_values_to: 連結欄位值至此網址
1002 label_custom_field_select_type: 請選擇連結此自訂欄位的物件類型
1001 label_custom_field_select_type: 請選擇連結此自訂欄位的物件類型
1003 label_check_for_updates: 檢查更新
1002 label_check_for_updates: 檢查更新
@@ -1196,3 +1195,4
1196 description_date_from: 輸入起始日期
1195 description_date_from: 輸入起始日期
1197 description_date_to: 輸入結束日期
1196 description_date_to: 輸入結束日期
1198 text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。<br />一旦儲存之後, 代碼便無法再次被更改。'
1197 text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。<br />一旦儲存之後, 代碼便無法再次被更改。'
1198 label_radio_buttons: radio buttons
@@ -15,7 +15,7
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 RedmineApp::Application.routes.draw do
18 Rails.application.routes.draw do
19 root :to => 'welcome#index', :as => 'home'
19 root :to => 'welcome#index', :as => 'home'
20
20
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
21 match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post]
@@ -25,10 +25,10 RedmineApp::Application.routes.draw do
25 match 'account/activate', :to => 'account#activate', :via => :get
25 match 'account/activate', :to => 'account#activate', :via => :get
26 get 'account/activation_email', :to => 'account#activation_email', :as => 'activation_email'
26 get 'account/activation_email', :to => 'account#activation_email', :as => 'activation_email'
27
27
28 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put]
28 match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put, :patch]
29 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put]
29 match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put, :patch]
30 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put]
30 match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put, :patch]
31 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put]
31 match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put, :patch]
32
32
33 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
33 match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post
34 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
34 match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post]
@@ -74,7 +74,7 RedmineApp::Application.routes.draw do
74 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
74 match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post
75
75
76 resources :users
76 resources :users
77 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership'
77 match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => [:put, :patch], :as => 'user_membership'
78 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
78 match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete
79 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
79 match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships'
80
80
@@ -113,7 +113,7 RedmineApp::Application.routes.draw do
113 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
113 get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue'
114 resources :issues, :only => [:index, :new, :create]
114 resources :issues, :only => [:index, :new, :create]
115 # issue form update
115 # issue form update
116 match 'issues/update_form', :controller => 'issues', :action => 'update_form', :via => [:put, :post], :as => 'issue_form'
116 match 'issues/update_form', :controller => 'issues', :action => 'update_form', :via => [:put, :patch, :post], :as => 'issue_form'
117
117
118 resources :files, :only => [:index, :new, :create]
118 resources :files, :only => [:index, :new, :create]
119
119
@@ -151,7 +151,7 RedmineApp::Application.routes.draw do
151 post 'rename'
151 post 'rename'
152 get 'history'
152 get 'history'
153 get 'diff'
153 get 'diff'
154 match 'preview', :via => [:post, :put]
154 match 'preview', :via => [:post, :put, :patch]
155 post 'protect'
155 post 'protect'
156 post 'add_attachment'
156 post 'add_attachment'
157 end
157 end
@@ -17,7 +17,10
17
17
18 class Setup < ActiveRecord::Migration
18 class Setup < ActiveRecord::Migration
19
19
20 class User < ActiveRecord::Base; end
20 class User < ActiveRecord::Base
21 attr_protected :id
22 end
23
21 # model removed
24 # model removed
22 class Permission < ActiveRecord::Base; end
25 class Permission < ActiveRecord::Base; end
23
26
@@ -4,7 +4,7 class AddEnumerationsPosition < ActiveRecord::Migration
4 Enumeration.all.group_by(&:opt).each do |opt, enums|
4 Enumeration.all.group_by(&:opt).each do |opt, enums|
5 enums.each_with_index do |enum, i|
5 enums.each_with_index do |enum, i|
6 # do not call model callbacks
6 # do not call model callbacks
7 Enumeration.update_all "position = #{i+1}", {:id => enum.id}
7 Enumeration.where({:id => enum.id}).update_all("position = #{i+1}")
8 end
8 end
9 end
9 end
10 end
10 end
@@ -4,7 +4,7 class AddCustomFieldsPosition < ActiveRecord::Migration
4 CustomField.all.group_by(&:type).each do |t, fields|
4 CustomField.all.group_by(&:type).each do |t, fields|
5 fields.each_with_index do |field, i|
5 fields.each_with_index do |field, i|
6 # do not call model callbacks
6 # do not call model callbacks
7 CustomField.update_all "position = #{i+1}", {:id => field.id}
7 CustomField.where({:id => field.id}).update_all("position = #{i+1}")
8 end
8 end
9 end
9 end
10 end
10 end
@@ -7,7 +7,7 class PopulateChangesetsUserId < ActiveRecord::Migration
7 username, email = $1.strip, $3
7 username, email = $1.strip, $3
8 u = User.find_by_login(username)
8 u = User.find_by_login(username)
9 u ||= User.find_by_mail(email) unless email.blank?
9 u ||= User.find_by_mail(email) unless email.blank?
10 Changeset.update_all("user_id = #{u.id}", ["committer = ?", committer]) unless u.nil?
10 Changeset.where(["committer = ?", committer]).update_all("user_id = #{u.id}") unless u.nil?
11 end
11 end
12 end
12 end
13 end
13 end
@@ -5,8 +5,8 class RemoveEnumerationsOpt < ActiveRecord::Migration
5
5
6 def self.down
6 def self.down
7 add_column :enumerations, :opt, :string, :limit => 4, :default => '', :null => false
7 add_column :enumerations, :opt, :string, :limit => 4, :default => '', :null => false
8 Enumeration.update_all("opt = 'IPRI'", "type = 'IssuePriority'")
8 Enumeration.where("type = 'IssuePriority'").update_all("opt = 'IPRI'")
9 Enumeration.update_all("opt = 'DCAT'", "type = 'DocumentCategory'")
9 Enumeration.where("type = 'DocumentCategory'").update_all("opt = 'DCAT'")
10 Enumeration.update_all("opt = 'ACTI'", "type = 'TimeEntryActivity'")
10 Enumeration.where("type = 'TimeEntryActivity'").update_all("opt = 'ACTI'")
11 end
11 end
12 end
12 end
@@ -1,6 +1,6
1 class EnableCalendarAndGanttModulesWhereAppropriate < ActiveRecord::Migration
1 class EnableCalendarAndGanttModulesWhereAppropriate < ActiveRecord::Migration
2 def self.up
2 def self.up
3 EnabledModule.where(:name => 'issue_tracking').all.each do |e|
3 EnabledModule.where(:name => 'issue_tracking').each do |e|
4 EnabledModule.create(:name => 'calendar', :project_id => e.project_id)
4 EnabledModule.create(:name => 'calendar', :project_id => e.project_id)
5 EnabledModule.create(:name => 'gantt', :project_id => e.project_id)
5 EnabledModule.create(:name => 'gantt', :project_id => e.project_id)
6 end
6 end
@@ -15,7 +15,8 class PopulateIssuesClosedOn < ActiveRecord::Migration
15
15
16 # Then set closed_on for closed issues that weren't up updated by the above UPDATE
16 # Then set closed_on for closed issues that weren't up updated by the above UPDATE
17 # No journal was found so we assume that they were closed on creation
17 # No journal was found so we assume that they were closed on creation
18 Issue.update_all "closed_on = created_on", {:status_id => closed_status_ids, :closed_on => nil}
18 Issue.where({:status_id => closed_status_ids, :closed_on => nil}).
19 update_all("closed_on = created_on")
19 end
20 end
20 end
21 end
21
22
@@ -86,7 +86,7 http://www.redmine.org/
86 * Defect #16655: start_date not set despite settings[default_issue_start_date_to_creation_date] being set.
86 * Defect #16655: start_date not set despite settings[default_issue_start_date_to_creation_date] being set.
87 * Defect #16668: Redmine links broken when object name contains special characters
87 * Defect #16668: Redmine links broken when object name contains special characters
88 * Defect #16669: Markdown formatter should use the :no_intra_emphasis extension
88 * Defect #16669: Markdown formatter should use the :no_intra_emphasis extension
89 * Defect #16708: Form is submitted when switching tab
89 * Defect #16708: Form is submitted when swithing tab
90 * Defect #16739: custom_fields.json only returns single tracker instead of array of trackers
90 * Defect #16739: custom_fields.json only returns single tracker instead of array of trackers
91 * Defect #16747: Remove useless settings when editing a query from the gantt
91 * Defect #16747: Remove useless settings when editing a query from the gantt
92 * Defect #16755: Field set as read-only still available in the issues list context menu
92 * Defect #16755: Field set as read-only still available in the issues list context menu
@@ -7,7 +7,7 http://www.redmine.org/
7
7
8 == Requirements
8 == Requirements
9
9
10 * Ruby 1.8.7, 1.9.2, 1.9.3, 2.0 or 2.1
10 * Ruby >= 1.9.3
11 * RubyGems
11 * RubyGems
12 * Bundler >= 1.0.21
12 * Bundler >= 1.0.21
13
13
@@ -30,9 +30,6 Optional:
30 3. Configure the database parameters in config/database.yml
30 3. Configure the database parameters in config/database.yml
31 for the "production" environment (default database is MySQL and ruby1.9)
31 for the "production" environment (default database is MySQL and ruby1.9)
32
32
33 If you're running Redmine with MySQL and ruby1.8, replace the adapter name
34 with `mysql`
35
36 4. Install the required gems by running:
33 4. Install the required gems by running:
37 bundle install --without development test
34 bundle install --without development test
38
35
@@ -29,7 +29,7 module Redmine
29 send :include, Redmine::Acts::ActivityProvider::InstanceMethods
29 send :include, Redmine::Acts::ActivityProvider::InstanceMethods
30 end
30 end
31
31
32 options.assert_valid_keys(:type, :permission, :timestamp, :author_key, :find_options)
32 options.assert_valid_keys(:type, :permission, :timestamp, :author_key, :find_options, :scope)
33 self.activity_provider_options ||= {}
33 self.activity_provider_options ||= {}
34
34
35 # One model can provide different event types
35 # One model can provide different event types
@@ -54,7 +54,7 module Redmine
54 provider_options = activity_provider_options[event_type]
54 provider_options = activity_provider_options[event_type]
55 raise "#{self.name} can not provide #{event_type} events." if provider_options.nil?
55 raise "#{self.name} can not provide #{event_type} events." if provider_options.nil?
56
56
57 scope = self
57 scope = (provider_options[:scope] || self)
58
58
59 if from && to
59 if from && to
60 scope = scope.where("#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to)
60 scope = scope.where("#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to)
@@ -79,7 +79,7 module Redmine
79 scope = scope.where(Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym, options))
79 scope = scope.where(Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym, options))
80 end
80 end
81
81
82 scope.all(provider_options[:find_options].dup)
82 scope.to_a
83 end
83 end
84 end
84 end
85 end
85 end
@@ -29,9 +29,8 module Redmine
29 attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym
29 attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym
30 attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
30 attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym
31
31
32 has_many :attachments, options.merge(:as => :container,
32 has_many :attachments, lambda {order("#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC")},
33 :order => "#{Attachment.table_name}.created_on ASC, #{Attachment.table_name}.id ASC",
33 options.merge(:as => :container, :dependent => :destroy)
34 :dependent => :destroy)
35 send :include, Redmine::Acts::Attachable::InstanceMethods
34 send :include, Redmine::Acts::Attachable::InstanceMethods
36 before_save :attach_saved_attachments
35 before_save :attach_saved_attachments
37 end
36 end
@@ -27,9 +27,8 module Redmine
27 return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
27 return if self.included_modules.include?(Redmine::Acts::Customizable::InstanceMethods)
28 cattr_accessor :customizable_options
28 cattr_accessor :customizable_options
29 self.customizable_options = options
29 self.customizable_options = options
30 has_many :custom_values, :as => :customized,
30 has_many :custom_values, lambda {includes(:custom_field).order("#{CustomField.table_name}.position")},
31 :include => :custom_field,
31 :as => :customized,
32 :order => "#{CustomField.table_name}.position",
33 :dependent => :delete_all,
32 :dependent => :delete_all,
34 :validate => false
33 :validate => false
35
34
@@ -46,7 +45,7 module Redmine
46 end
45 end
47
46
48 def available_custom_fields
47 def available_custom_fields
49 CustomField.where("type = '#{self.class.name}CustomField'").sorted.all
48 CustomField.where("type = '#{self.class.name}CustomField'").sorted.to_a
50 end
49 end
51
50
52 # Sets the values of the object's custom fields
51 # Sets the values of the object's custom fields
@@ -31,6 +31,7 module Redmine
31 # * :permission - permission required to search the model (default to :view_"objects")
31 # * :permission - permission required to search the model (default to :view_"objects")
32 def acts_as_searchable(options = {})
32 def acts_as_searchable(options = {})
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
33 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
34 options.assert_valid_keys(:columns, :project_key, :date_column, :order_column, :search_custom_fields, :permission, :scope)
34
35
35 cattr_accessor :searchable_options
36 cattr_accessor :searchable_options
36 self.searchable_options = options
37 self.searchable_options = options
@@ -70,7 +71,7 module Redmine
70 # TODO: make user an argument
71 # TODO: make user an argument
71 user = User.current
72 user = User.current
72 tokens = [] << tokens unless tokens.is_a?(Array)
73 tokens = [] << tokens unless tokens.is_a?(Array)
73 projects = [] << projects unless projects.nil? || projects.is_a?(Array)
74 projects = [] << projects if projects.is_a?(Project)
74
75
75 limit_options = {}
76 limit_options = {}
76 limit_options[:limit] = options[:limit] if options[:limit]
77 limit_options[:limit] = options[:limit] if options[:limit]
@@ -100,7 +101,10 module Redmine
100
101
101 tokens_conditions = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
102 tokens_conditions = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
102
103
103 scope = self.scoped
104 scope = (searchable_options[:scope] || self)
105 if scope.is_a? Proc
106 scope = scope.call
107 end
104 project_conditions = []
108 project_conditions = []
105 if searchable_options.has_key?(:permission)
109 if searchable_options.has_key?(:permission)
106 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project)
110 project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project)
@@ -118,10 +122,11 module Redmine
118 results_count = 0
122 results_count = 0
119
123
120 scope = scope.
124 scope = scope.
121 includes(searchable_options[:include]).
125 joins(searchable_options[:include]).
122 order("#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')).
126 order("#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')).
123 where(project_conditions).
127 where(project_conditions).
124 where(tokens_conditions)
128 where(tokens_conditions).
129 uniq
125
130
126 results_count = scope.count
131 results_count = scope.count
127
132
@@ -129,7 +134,7 module Redmine
129 if options[:offset]
134 if options[:offset]
130 scope_with_limit = scope_with_limit.where("#{searchable_options[:date_column]} #{options[:before] ? '<' : '>'} ?", options[:offset])
135 scope_with_limit = scope_with_limit.where("#{searchable_options[:date_column]} #{options[:before] ? '<' : '>'} ?", options[:offset])
131 end
136 end
132 results = scope_with_limit.all
137 results = scope_with_limit.to_a
133
138
134 [results, results_count]
139 [results, results_count]
135 end
140 end
@@ -44,7 +44,7 module ActiveRecord
44 configuration.update(options) if options.is_a?(Hash)
44 configuration.update(options) if options.is_a?(Hash)
45
45
46 belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
46 belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache]
47 has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent]
47 has_many :children, lambda {order(configuration[:order])}, :class_name => name, :foreign_key => configuration[:foreign_key], :dependent => configuration[:dependent]
48
48
49 scope :roots, lambda {
49 scope :roots, lambda {
50 where("#{configuration[:foreign_key]} IS NULL").
50 where("#{configuration[:foreign_key]} IS NULL").
@@ -68,7 +68,7 module Redmine
68 end
68 end
69
69
70 def notified_watchers
70 def notified_watchers
71 notified = watcher_users.active
71 notified = watcher_users.active.to_a
72 notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
72 notified.reject! {|user| user.mail.blank? || user.mail_notification == 'none'}
73 if respond_to?(:visible?)
73 if respond_to?(:visible?)
74 notified.reject! {|user| !visible?(user)}
74 notified.reject! {|user| !visible?(user)}
@@ -63,12 +63,7 require 'redmine/themes'
63 require 'redmine/hook'
63 require 'redmine/hook'
64 require 'redmine/plugin'
64 require 'redmine/plugin'
65
65
66 if RUBY_VERSION < '1.9'
67 require 'fastercsv'
68 else
69 require 'csv'
66 require 'csv'
70 FCSV = CSV
71 end
72
67
73 Redmine::Scm::Base.add "Subversion"
68 Redmine::Scm::Base.add "Subversion"
74 Redmine::Scm::Base.add "Darcs"
69 Redmine::Scm::Base.add "Darcs"
@@ -58,9 +58,11 module Redmine
58 if action.is_a?(Symbol)
58 if action.is_a?(Symbol)
59 perm = permission(action)
59 perm = permission(action)
60 !perm.nil? && perm.read?
60 !perm.nil? && perm.read?
61 else
61 elsif action.is_a?(Hash)
62 s = "#{action[:controller]}/#{action[:action]}"
62 s = "#{action[:controller]}/#{action[:action]}"
63 permissions.detect {|p| p.actions.include?(s) && p.read?}.present?
63 permissions.detect {|p| p.actions.include?(s) && p.read?}.present?
64 else
65 raise ArgumentError.new("Symbol or a Hash expected, #{action.class.name} given: #{action}")
64 end
66 end
65 end
67 end
66
68
@@ -1,51 +1,25
1 if RUBY_VERSION < '1.9'
2 require 'iconv'
3 end
4
1
5 module Redmine
2 module Redmine
6 module CodesetUtil
3 module CodesetUtil
7
4
8 def self.replace_invalid_utf8(str)
5 def self.replace_invalid_utf8(str)
9 return str if str.nil?
6 return str if str.nil?
10 if str.respond_to?(:force_encoding)
11 str.force_encoding('UTF-8')
7 str.force_encoding('UTF-8')
12 if ! str.valid_encoding?
8 if ! str.valid_encoding?
13 str = str.encode("US-ASCII", :invalid => :replace,
9 str = str.encode("US-ASCII", :invalid => :replace,
14 :undef => :replace, :replace => '?').encode("UTF-8")
10 :undef => :replace, :replace => '?').encode("UTF-8")
15 end
11 end
16 elsif RUBY_PLATFORM == 'java'
17 begin
18 ic = Iconv.new('UTF-8', 'UTF-8')
19 str = ic.iconv(str)
20 rescue
21 str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
22 end
23 else
24 ic = Iconv.new('UTF-8', 'UTF-8')
25 txtar = ""
26 begin
27 txtar += ic.iconv(str)
28 rescue Iconv::IllegalSequence
29 txtar += $!.success
30 str = '?' + $!.failed[1,$!.failed.length]
31 retry
32 rescue
33 txtar += $!.success
34 end
35 str = txtar
36 end
37 str
12 str
38 end
13 end
39
14
40 def self.to_utf8(str, encoding)
15 def self.to_utf8(str, encoding)
41 return str if str.nil?
16 return str if str.nil?
42 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
17 str.force_encoding("ASCII-8BIT")
43 if str.empty?
18 if str.empty?
44 str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
19 str.force_encoding("UTF-8")
45 return str
20 return str
46 end
21 end
47 enc = encoding.blank? ? "UTF-8" : encoding
22 enc = encoding.blank? ? "UTF-8" : encoding
48 if str.respond_to?(:force_encoding)
49 if enc.upcase != "UTF-8"
23 if enc.upcase != "UTF-8"
50 str.force_encoding(enc)
24 str.force_encoding(enc)
51 str = str.encode("UTF-8", :invalid => :replace,
25 str = str.encode("UTF-8", :invalid => :replace,
@@ -57,52 +31,22 module Redmine
57 :undef => :replace, :replace => '?').encode("UTF-8")
31 :undef => :replace, :replace => '?').encode("UTF-8")
58 end
32 end
59 end
33 end
60 elsif RUBY_PLATFORM == 'java'
61 begin
62 ic = Iconv.new('UTF-8', enc)
63 str = ic.iconv(str)
64 rescue
65 str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
66 end
67 else
68 ic = Iconv.new('UTF-8', enc)
69 txtar = ""
70 begin
71 txtar += ic.iconv(str)
72 rescue Iconv::IllegalSequence
73 txtar += $!.success
74 str = '?' + $!.failed[1,$!.failed.length]
75 retry
76 rescue
77 txtar += $!.success
78 end
79 str = txtar
80 end
81 str
34 str
82 end
35 end
83
36
84 def self.to_utf8_by_setting(str)
37 def self.to_utf8_by_setting(str)
85 return str if str.nil?
38 return str if str.nil?
86 str = self.to_utf8_by_setting_internal(str)
39 self.to_utf8_by_setting_internal(str).force_encoding('UTF-8')
87 if str.respond_to?(:force_encoding)
88 str.force_encoding('UTF-8')
89 end
90 str
91 end
40 end
92
41
93 def self.to_utf8_by_setting_internal(str)
42 def self.to_utf8_by_setting_internal(str)
94 return str if str.nil?
43 return str if str.nil?
95 if str.respond_to?(:force_encoding)
96 str.force_encoding('ASCII-8BIT')
44 str.force_encoding('ASCII-8BIT')
97 end
98 return str if str.empty?
45 return str if str.empty?
99 return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
46 return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
100 if str.respond_to?(:force_encoding)
101 str.force_encoding('UTF-8')
47 str.force_encoding('UTF-8')
102 end
103 encodings = Setting.repositories_encodings.split(',').collect(&:strip)
48 encodings = Setting.repositories_encodings.split(',').collect(&:strip)
104 encodings.each do |encoding|
49 encodings.each do |encoding|
105 if str.respond_to?(:force_encoding)
106 begin
50 begin
107 str.force_encoding(encoding)
51 str.force_encoding(encoding)
108 utf8 = str.encode('UTF-8')
52 utf8 = str.encode('UTF-8')
@@ -110,24 +54,12 module Redmine
110 rescue
54 rescue
111 # do nothing here and try the next encoding
55 # do nothing here and try the next encoding
112 end
56 end
113 else
114 begin
115 return Iconv.conv('UTF-8', encoding, str)
116 rescue Iconv::Failure
117 # do nothing here and try the next encoding
118 end
119 end
120 end
121 str = self.replace_invalid_utf8(str)
122 if str.respond_to?(:force_encoding)
123 str.force_encoding('UTF-8')
124 end
57 end
125 str
58 self.replace_invalid_utf8(str).force_encoding('UTF-8')
126 end
59 end
127
60
128 def self.from_utf8(str, encoding)
61 def self.from_utf8(str, encoding)
129 str ||= ''
62 str ||= ''
130 if str.respond_to?(:force_encoding)
131 str.force_encoding('UTF-8')
63 str.force_encoding('UTF-8')
132 if encoding.upcase != 'UTF-8'
64 if encoding.upcase != 'UTF-8'
133 str = str.encode(encoding, :invalid => :replace,
65 str = str.encode(encoding, :invalid => :replace,
@@ -135,27 +67,6 module Redmine
135 else
67 else
136 str = self.replace_invalid_utf8(str)
68 str = self.replace_invalid_utf8(str)
137 end
69 end
138 elsif RUBY_PLATFORM == 'java'
139 begin
140 ic = Iconv.new(encoding, 'UTF-8')
141 str = ic.iconv(str)
142 rescue
143 str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?')
144 end
145 else
146 ic = Iconv.new(encoding, 'UTF-8')
147 txtar = ""
148 begin
149 txtar += ic.iconv(str)
150 rescue Iconv::IllegalSequence
151 txtar += $!.success
152 str = '?' + $!.failed[1, $!.failed.length]
153 retry
154 rescue
155 txtar += $!.success
156 end
157 str = txtar
158 end
159 end
70 end
160 end
71 end
161 end
72 end
@@ -15,35 +15,10
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module ActiveRecord
19 module FinderMethods
20 def find_ids(*args)
21 find_ids_with_associations
22 end
23
24 private
25
26 def find_ids_with_associations
27 join_dependency = construct_join_dependency_for_association_find
28 relation = construct_relation_for_association_find_ids(join_dependency)
29 rows = connection.select_all(relation, 'SQL', relation.bind_values)
30 rows.map {|row| row["id"].to_i}
31 rescue ThrowResult
32 []
33 end
34
35 def construct_relation_for_association_find_ids(join_dependency)
36 relation = except(:includes, :eager_load, :preload, :select).select("#{table_name}.id")
37 apply_join_dependency(relation, join_dependency)
38 end
39 end
40 end
41
42 class DateValidator < ActiveModel::EachValidator
18 class DateValidator < ActiveModel::EachValidator
43 def validate_each(record, attribute, value)
19 def validate_each(record, attribute, value)
44 before_type_cast = record.attributes_before_type_cast[attribute.to_s]
20 before_type_cast = record.attributes_before_type_cast[attribute.to_s]
45 if before_type_cast.is_a?(String) && before_type_cast.present?
21 if before_type_cast.is_a?(String) && before_type_cast.present?
46 # TODO: #*_date_before_type_cast returns a Mysql::Time with ruby1.8+mysql gem
47 unless before_type_cast =~ /\A\d{4}-\d{2}-\d{2}( 00:00:00)?\z/ && value
22 unless before_type_cast =~ /\A\d{4}-\d{2}-\d{2}( 00:00:00)?\z/ && value
48 record.errors.add attribute, :not_a_date
23 record.errors.add attribute, :not_a_date
49 end
24 end
@@ -36,13 +36,6 module Redmine #:nodoc:
36 s.gsub!(',', '.')
36 s.gsub!(',', '.')
37 begin; Kernel.Float(s); rescue; nil; end
37 begin; Kernel.Float(s); rescue; nil; end
38 end
38 end
39
40 # Object#to_a removed in ruby1.9
41 if RUBY_VERSION > '1.9'
42 def to_a
43 [self.dup]
44 end
45 end
46 end
39 end
47 end
40 end
48 end
41 end
@@ -678,9 +678,7 module Redmine
678 def self.rdm_from_utf8(txt, encoding)
678 def self.rdm_from_utf8(txt, encoding)
679 txt ||= ''
679 txt ||= ''
680 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
680 txt = Redmine::CodesetUtil.from_utf8(txt, encoding)
681 if txt.respond_to?(:force_encoding)
682 txt.force_encoding('ASCII-8BIT')
681 txt.force_encoding('ASCII-8BIT')
683 end
684 txt
682 txt
685 end
683 end
686
684
@@ -598,17 +598,12 module Redmine
598 @target_class ||= self.class.name[/^(.*::)?(.+)Format$/, 2].constantize rescue nil
598 @target_class ||= self.class.name[/^(.*::)?(.+)Format$/, 2].constantize rescue nil
599 end
599 end
600
600
601 def reset_target_class
602 @target_class = nil
603 end
604
605 def possible_custom_value_options(custom_value)
601 def possible_custom_value_options(custom_value)
606 options = possible_values_options(custom_value.custom_field, custom_value.customized)
602 options = possible_values_options(custom_value.custom_field, custom_value.customized)
607 missing = [custom_value.value_was].flatten.reject(&:blank?) - options.map(&:last)
603 missing = [custom_value.value_was].flatten.reject(&:blank?) - options.map(&:last)
608 if missing.any?
604 if missing.any?
609 options += target_class.where(:id => missing.map(&:to_i)).map {|o| [o.to_s, o.id.to_s]}
605 options += target_class.where(:id => missing.map(&:to_i)).map {|o| [o.to_s, o.id.to_s]}
610 #TODO: use #sort_by! when ruby1.8 support is dropped
606 options.sort_by!(&:first)
611 options = options.sort_by(&:first)
612 end
607 end
613 options
608 options
614 end
609 end
@@ -167,7 +167,7 module Redmine
167 where("child.id IN (?)", ids).
167 where("child.id IN (?)", ids).
168 order("#{Project.table_name}.lft ASC").
168 order("#{Project.table_name}.lft ASC").
169 uniq.
169 uniq.
170 all
170 to_a
171 else
171 else
172 @projects = []
172 @projects = []
173 end
173 end
@@ -193,7 +193,7 module Redmine
193 # * Checking the url target (project only)
193 # * Checking the url target (project only)
194 # * Checking the conditions of the item
194 # * Checking the conditions of the item
195 def allowed_node?(node, user, project)
195 def allowed_node?(node, user, project)
196 if project && user && !user.allowed_to?(node.url, project)
196 if node.url.is_a?(Hash) && project && user && !user.allowed_to?(node.url, project)
197 return false
197 return false
198 end
198 end
199 if node.condition && !node.condition.call(project)
199 if node.condition && !node.condition.call(project)
@@ -18,17 +18,13
18 require 'cgi'
18 require 'cgi'
19 require 'redmine/scm/adapters'
19 require 'redmine/scm/adapters'
20
20
21 if RUBY_VERSION < '1.9'
22 require 'iconv'
23 end
24
25 module Redmine
21 module Redmine
26 module Scm
22 module Scm
27 module Adapters
23 module Adapters
28 class AbstractAdapter #:nodoc:
24 class AbstractAdapter #:nodoc:
29
25
30 # raised if scm command exited with error, e.g. unknown revision.
26 # raised if scm command exited with error, e.g. unknown revision.
31 class ScmCommandAborted < CommandFailed; end
27 class ScmCommandAborted < ::Redmine::Scm::Adapters::CommandFailed; end
32
28
33 class << self
29 class << self
34 def client_command
30 def client_command
@@ -288,7 +284,6 module Redmine
288 def scm_iconv(to, from, str)
284 def scm_iconv(to, from, str)
289 return nil if str.nil?
285 return nil if str.nil?
290 return str if to == from
286 return str if to == from
291 if str.respond_to?(:force_encoding)
292 str.force_encoding(from)
287 str.force_encoding(from)
293 begin
288 begin
294 str.encode(to)
289 str.encode(to)
@@ -296,14 +291,6 module Redmine
296 logger.error("failed to convert from #{from} to #{to}. #{err}")
291 logger.error("failed to convert from #{from} to #{to}. #{err}")
297 nil
292 nil
298 end
293 end
299 else
300 begin
301 Iconv.conv(to, from, str)
302 rescue Iconv::Failure => err
303 logger.error("failed to convert from #{from} to #{to}. #{err}")
304 nil
305 end
306 end
307 end
294 end
308
295
309 def parse_xml(xml)
296 def parse_xml(xml)
@@ -43,10 +43,7 module Redmine
43 end
43 end
44
44
45 def scm_command_version
45 def scm_command_version
46 scm_version = scm_version_from_command_line.dup
46 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
47 if scm_version.respond_to?(:force_encoding)
48 scm_version.force_encoding('ASCII-8BIT')
49 end
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
47 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
51 m[2].scan(%r{\d+}).collect(&:to_i)
48 m[2].scan(%r{\d+}).collect(&:to_i)
52 end
49 end
@@ -100,7 +97,7 module Redmine
100 prefix_utf8 = "#{url}/#{path}".gsub('\\', '/')
97 prefix_utf8 = "#{url}/#{path}".gsub('\\', '/')
101 logger.debug "PREFIX: #{prefix_utf8}"
98 logger.debug "PREFIX: #{prefix_utf8}"
102 prefix = scm_iconv(@path_encoding, 'UTF-8', prefix_utf8)
99 prefix = scm_iconv(@path_encoding, 'UTF-8', prefix_utf8)
103 prefix.force_encoding('ASCII-8BIT') if prefix.respond_to?(:force_encoding)
100 prefix.force_encoding('ASCII-8BIT')
104 re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$}
101 re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$}
105 io.each_line do |line|
102 io.each_line do |line|
106 next unless line =~ re
103 next unless line =~ re
@@ -43,10 +43,7 module Redmine
43 end
43 end
44
44
45 def scm_command_version
45 def scm_command_version
46 scm_version = scm_version_from_command_line.dup
46 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
47 if scm_version.respond_to?(:force_encoding)
48 scm_version.force_encoding('ASCII-8BIT')
49 end
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m)
47 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m)
51 m[2].scan(%r{\d+}).collect(&:to_i)
48 m[2].scan(%r{\d+}).collect(&:to_i)
52 end
49 end
@@ -94,7 +91,7 module Redmine
94 def entries(path=nil, identifier=nil, options={})
91 def entries(path=nil, identifier=nil, options={})
95 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
92 logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
96 path_locale = scm_iconv(@path_encoding, 'UTF-8', path)
93 path_locale = scm_iconv(@path_encoding, 'UTF-8', path)
97 path_locale.force_encoding("ASCII-8BIT") if path_locale.respond_to?(:force_encoding)
94 path_locale.force_encoding("ASCII-8BIT")
98 entries = Entries.new
95 entries = Entries.new
99 cmd_args = %w|-q rls -e|
96 cmd_args = %w|-q rls -e|
100 cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier
97 cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier
@@ -171,6 +168,7 module Redmine
171 file_state = nil
168 file_state = nil
172 branch_map = nil
169 branch_map = nil
173 io.each_line() do |line|
170 io.each_line() do |line|
171 line = line.strip
174 if state != "revision" && /^#{ENDLOG}/ =~ line
172 if state != "revision" && /^#{ENDLOG}/ =~ line
175 commit_log = String.new
173 commit_log = String.new
176 revision = nil
174 revision = nil
@@ -43,10 +43,7 module Redmine
43 end
43 end
44
44
45 def darcs_binary_version
45 def darcs_binary_version
46 darcsversion = darcs_binary_version_from_command_line.dup
46 darcsversion = darcs_binary_version_from_command_line.dup.force_encoding('ASCII-8BIT')
47 if darcsversion.respond_to?(:force_encoding)
48 darcsversion.force_encoding('ASCII-8BIT')
49 end
50 if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)})
47 if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)})
51 m[2].scan(%r{\d+}).collect(&:to_i)
48 m[2].scan(%r{\d+}).collect(&:to_i)
52 end
49 end
@@ -47,10 +47,7 module Redmine
47 end
47 end
48
48
49 def scm_command_version
49 def scm_command_version
50 scm_version = scm_version_from_command_line.dup
50 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
51 if scm_version.respond_to?(:force_encoding)
52 scm_version.force_encoding('ASCII-8BIT')
53 end
54 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
51 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
55 m[2].scan(%r{\d+}).collect(&:to_i)
52 m[2].scan(%r{\d+}).collect(&:to_i)
56 end
53 end
@@ -145,10 +142,7 module Redmine
145 type = $1
142 type = $1
146 sha = $2
143 sha = $2
147 size = $3
144 size = $3
148 name = $4
145 name = $4.force_encoding(@path_encoding)
149 if name.respond_to?(:force_encoding)
150 name.force_encoding(@path_encoding)
151 end
152 full_path = p.empty? ? name : "#{p}/#{name}"
146 full_path = p.empty? ? name : "#{p}/#{name}"
153 n = scm_iconv('UTF-8', @path_encoding, name)
147 n = scm_iconv('UTF-8', @path_encoding, name)
154 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
148 full_p = scm_iconv('UTF-8', @path_encoding, full_path)
@@ -54,10 +54,7 module Redmine
54 # The hg version is expressed either as a
54 # The hg version is expressed either as a
55 # release number (eg 0.9.5 or 1.0) or as a revision
55 # release number (eg 0.9.5 or 1.0) or as a revision
56 # id composed of 12 hexa characters.
56 # id composed of 12 hexa characters.
57 theversion = hgversion_from_command_line.dup
57 theversion = hgversion_from_command_line.dup.force_encoding('ASCII-8BIT')
58 if theversion.respond_to?(:force_encoding)
59 theversion.force_encoding('ASCII-8BIT')
60 end
61 if m = theversion.match(%r{\A(.*?)((\d+\.)+\d+)})
58 if m = theversion.match(%r{\A(.*?)((\d+\.)+\d+)})
62 m[2].scan(%r{\d+}).collect(&:to_i)
59 m[2].scan(%r{\d+}).collect(&:to_i)
63 end
60 end
@@ -130,10 +127,7 module Redmine
130 def summary
127 def summary
131 return @summary if @summary
128 return @summary if @summary
132 hg 'rhsummary' do |io|
129 hg 'rhsummary' do |io|
133 output = io.read
130 output = io.read.force_encoding('UTF-8')
134 if output.respond_to?(:force_encoding)
135 output.force_encoding('UTF-8')
136 end
137 begin
131 begin
138 @summary = parse_xml(output)['rhsummary']
132 @summary = parse_xml(output)['rhsummary']
139 rescue
133 rescue
@@ -146,10 +140,7 module Redmine
146 p1 = scm_iconv(@path_encoding, 'UTF-8', path)
140 p1 = scm_iconv(@path_encoding, 'UTF-8', path)
147 manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)),
141 manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)),
148 CGI.escape(without_leading_slash(p1.to_s))) do |io|
142 CGI.escape(without_leading_slash(p1.to_s))) do |io|
149 output = io.read
143 output = io.read.force_encoding('UTF-8')
150 if output.respond_to?(:force_encoding)
151 output.force_encoding('UTF-8')
152 end
153 begin
144 begin
154 parse_xml(output)['rhmanifest']['repository']['manifest']
145 parse_xml(output)['rhmanifest']['repository']['manifest']
155 rescue
146 rescue
@@ -193,10 +184,7 module Redmine
193 hg_args << '--limit' << options[:limit] if options[:limit]
184 hg_args << '--limit' << options[:limit] if options[:limit]
194 hg_args << hgtarget(path) unless path.blank?
185 hg_args << hgtarget(path) unless path.blank?
195 log = hg(*hg_args) do |io|
186 log = hg(*hg_args) do |io|
196 output = io.read
187 output = io.read.force_encoding('UTF-8')
197 if output.respond_to?(:force_encoding)
198 output.force_encoding('UTF-8')
199 end
200 begin
188 begin
201 # Mercurial < 1.5 does not support footer template for '</log>'
189 # Mercurial < 1.5 does not support footer template for '</log>'
202 parse_xml("#{output}</log>")['log']
190 parse_xml("#{output}</log>")['log']
@@ -278,7 +266,7 module Redmine
278 blame = Annotate.new
266 blame = Annotate.new
279 hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
267 hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io|
280 io.each_line do |line|
268 io.each_line do |line|
281 line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding)
269 line.force_encoding('ASCII-8BIT')
282 next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$}
270 next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$}
283 r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3,
271 r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3,
284 :identifier => $3)
272 :identifier => $3)
@@ -46,10 +46,7 module Redmine
46 end
46 end
47
47
48 def svn_binary_version
48 def svn_binary_version
49 scm_version = scm_version_from_command_line.dup
49 scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
50 if scm_version.respond_to?(:force_encoding)
51 scm_version.force_encoding('ASCII-8BIT')
52 end
53 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
50 if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
54 m[2].scan(%r{\d+}).collect(&:to_i)
51 m[2].scan(%r{\d+}).collect(&:to_i)
55 end
52 end
@@ -66,10 +63,7 module Redmine
66 cmd << credentials_string
63 cmd << credentials_string
67 info = nil
64 info = nil
68 shellout(cmd) do |io|
65 shellout(cmd) do |io|
69 output = io.read
66 output = io.read.force_encoding('UTF-8')
70 if output.respond_to?(:force_encoding)
71 output.force_encoding('UTF-8')
72 end
73 begin
67 begin
74 doc = parse_xml(output)
68 doc = parse_xml(output)
75 # root_url = doc.elements["info/entry/repository/root"].text
69 # root_url = doc.elements["info/entry/repository/root"].text
@@ -98,10 +92,7 module Redmine
98 cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
92 cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
99 cmd << credentials_string
93 cmd << credentials_string
100 shellout(cmd) do |io|
94 shellout(cmd) do |io|
101 output = io.read
95 output = io.read.force_encoding('UTF-8')
102 if output.respond_to?(:force_encoding)
103 output.force_encoding('UTF-8')
104 end
105 begin
96 begin
106 doc = parse_xml(output)
97 doc = parse_xml(output)
107 each_xml_element(doc['lists']['list'], 'entry') do |entry|
98 each_xml_element(doc['lists']['list'], 'entry') do |entry|
@@ -141,10 +132,7 module Redmine
141 cmd << credentials_string
132 cmd << credentials_string
142 properties = {}
133 properties = {}
143 shellout(cmd) do |io|
134 shellout(cmd) do |io|
144 output = io.read
135 output = io.read.force_encoding('UTF-8')
145 if output.respond_to?(:force_encoding)
146 output.force_encoding('UTF-8')
147 end
148 begin
136 begin
149 doc = parse_xml(output)
137 doc = parse_xml(output)
150 each_xml_element(doc['properties']['target'], 'property') do |property|
138 each_xml_element(doc['properties']['target'], 'property') do |property|
@@ -168,10 +156,7 module Redmine
168 cmd << " --limit #{options[:limit].to_i}" if options[:limit]
156 cmd << " --limit #{options[:limit].to_i}" if options[:limit]
169 cmd << ' ' + target(path)
157 cmd << ' ' + target(path)
170 shellout(cmd) do |io|
158 shellout(cmd) do |io|
171 output = io.read
159 output = io.read.force_encoding('UTF-8')
172 if output.respond_to?(:force_encoding)
173 output.force_encoding('UTF-8')
174 end
175 begin
160 begin
176 doc = parse_xml(output)
161 doc = parse_xml(output)
177 each_xml_element(doc['log'], 'logentry') do |logentry|
162 each_xml_element(doc['log'], 'logentry') do |logentry|
@@ -199,28 +199,10 module Redmine
199 while starting < max && line_left[starting] == line_right[starting]
199 while starting < max && line_left[starting] == line_right[starting]
200 starting += 1
200 starting += 1
201 end
201 end
202 if (! "".respond_to?(:force_encoding)) && starting < line_left.size
203 while line_left[starting].ord.between?(128, 191) && starting > 0
204 starting -= 1
205 end
206 end
207 ending = -1
202 ending = -1
208 while ending >= -(max - starting) && (line_left[ending] == line_right[ending])
203 while ending >= -(max - starting) && (line_left[ending] == line_right[ending])
209 ending -= 1
204 ending -= 1
210 end
205 end
211 if (! "".respond_to?(:force_encoding)) && ending > (-1 * line_left.size)
212 while line_left[ending].ord.between?(128, 255) && ending < -1
213 if line_left[ending].ord.between?(128, 191)
214 if line_left[ending + 1].ord.between?(128, 191)
215 ending += 1
216 else
217 break
218 end
219 else
220 ending += 1
221 end
222 end
223 end
224 unless starting == 0 && ending == -1
206 unless starting == 0 && ending == -1
225 [starting, ending]
207 [starting, ending]
226 end
208 end
@@ -279,7 +261,7 module Redmine
279
261
280 def line_to_html(line, offsets)
262 def line_to_html(line, offsets)
281 html = line_to_html_raw(line, offsets)
263 html = line_to_html_raw(line, offsets)
282 html.force_encoding('UTF-8') if html.respond_to?(:force_encoding)
264 html.force_encoding('UTF-8')
283 html
265 html
284 end
266 end
285
267
@@ -33,7 +33,7 namespace :ci do
33 else
33 else
34 Rake::Task["test"].invoke
34 Rake::Task["test"].invoke
35 end
35 end
36 # Rake::Task["test:ui"].invoke if RUBY_VERSION >= '1.9.3'
36 # Rake::Task["test:ui"].invoke
37 end
37 end
38
38
39 desc "Finish the build"
39 desc "Finish the build"
@@ -52,7 +52,7 file 'config/database.yml' do
52
52
53 case database
53 case database
54 when 'mysql'
54 when 'mysql'
55 dev_conf = {'adapter' => (RUBY_VERSION >= '1.9' ? 'mysql2' : 'mysql'),
55 dev_conf = {'adapter' => 'mysql2',
56 'database' => dev_db_name, 'host' => 'localhost',
56 'database' => dev_db_name, 'host' => 'localhost',
57 'encoding' => 'utf8'}
57 'encoding' => 'utf8'}
58 if ENV['RUN_ON_NOT_OFFICIAL']
58 if ENV['RUN_ON_NOT_OFFICIAL']
@@ -68,9 +68,6 namespace :locales do
68 desc <<-END_DESC
68 desc <<-END_DESC
69 Removes a translation string from all locale file (only works for top-level childless non-multiline keys, probably doesn\'t work on windows).
69 Removes a translation string from all locale file (only works for top-level childless non-multiline keys, probably doesn\'t work on windows).
70
70
71 This task does not work on Ruby 1.8.6.
72 You need to use Ruby 1.8.7 or later.
73
74 Options:
71 Options:
75 key=key_1,key_2 Comma-separated list of keys to delete
72 key=key_1,key_2 Comma-separated list of keys to delete
76 skip=en,de Comma-separated list of locale files to ignore (filename without extension)
73 skip=en,de Comma-separated list of locale files to ignore (filename without extension)
@@ -18,7 +18,6
18 desc 'Mantis migration script'
18 desc 'Mantis migration script'
19
19
20 require 'active_record'
20 require 'active_record'
21 require 'iconv' if RUBY_VERSION < '1.9'
22 require 'pp'
21 require 'pp'
23
22
24 namespace :redmine do
23 namespace :redmine do
@@ -452,14 +451,9 task :migrate_from_mantis => :environment do
452 end
451 end
453
452
454 def self.encode(text)
453 def self.encode(text)
455 if RUBY_VERSION < '1.9'
456 @ic ||= Iconv.new('UTF-8', @charset)
457 @ic.iconv text
458 else
459 text.to_s.force_encoding(@charset).encode('UTF-8')
454 text.to_s.force_encoding(@charset).encode('UTF-8')
460 end
455 end
461 end
456 end
462 end
463
457
464 puts
458 puts
465 if Redmine::DefaultData::Loader.no_data?
459 if Redmine::DefaultData::Loader.no_data?
@@ -16,7 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'active_record'
18 require 'active_record'
19 require 'iconv' if RUBY_VERSION < '1.9'
20 require 'pp'
19 require 'pp'
21
20
22 namespace :redmine do
21 namespace :redmine do
@@ -155,7 +154,7 namespace :redmine do
155 attachment_type = read_attribute(:type)
154 attachment_type = read_attribute(:type)
156 #replace exotic characters with their hex representation to avoid invalid filenames
155 #replace exotic characters with their hex representation to avoid invalid filenames
157 trac_file = filename.gsub( /[^a-zA-Z0-9\-_\.!~*']/n ) do |x|
156 trac_file = filename.gsub( /[^a-zA-Z0-9\-_\.!~*']/n ) do |x|
158 codepoint = RUBY_VERSION < '1.9' ? x[0] : x.codepoints.to_a[0]
157 codepoint = x.codepoints.to_a[0]
159 sprintf('%%%02x', codepoint)
158 sprintf('%%%02x', codepoint)
160 end
159 end
161 "#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}"
160 "#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}"
@@ -715,14 +714,9 namespace :redmine do
715 end
714 end
716
715
717 def self.encode(text)
716 def self.encode(text)
718 if RUBY_VERSION < '1.9'
719 @ic ||= Iconv.new('UTF-8', @charset)
720 @ic.iconv text
721 else
722 text.to_s.force_encoding(@charset).encode('UTF-8')
717 text.to_s.force_encoding(@charset).encode('UTF-8')
723 end
718 end
724 end
719 end
725 end
726
720
727 puts
721 puts
728 if Redmine::DefaultData::Loader.no_data?
722 if Redmine::DefaultData::Loader.no_data?
@@ -1,6 +1,2
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2
2 abort "script/about no longer exists, please use bin/about instead."
3 ENV["RAILS_ENV"] ||= "production"
4 require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
5 puts
6 puts Redmine::Info.environment
@@ -1,6 +1,2
1 #!/usr/bin/env ruby
1 #!/usr/bin/env ruby
2 # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
2 abort "script/rails no longer exists, please use bin/rails instead."
3
4 APP_PATH = File.expand_path('../../config/application', __FILE__)
5 require File.expand_path('../../config/boot', __FILE__)
6 require 'rails/commands'
@@ -72,8 +72,8 class AccountControllerTest < ActionController::TestCase
72 end
72 end
73
73
74 def test_login_with_suburi_should_redirect_to_back_url_param
74 def test_login_with_suburi_should_redirect_to_back_url_param
75 @relative_url_root = ApplicationController.relative_url_root
75 @relative_url_root = Redmine::Utils.relative_url_root
76 ApplicationController.relative_url_root = '/redmine'
76 Redmine::Utils.relative_url_root = '/redmine'
77
77
78 back_urls = [
78 back_urls = [
79 'http://test.host/redmine/issues/show/1',
79 'http://test.host/redmine/issues/show/1',
@@ -84,7 +84,7 class AccountControllerTest < ActionController::TestCase
84 assert_redirected_to back_url
84 assert_redirected_to back_url
85 end
85 end
86 ensure
86 ensure
87 ApplicationController.relative_url_root = @relative_url_root
87 Redmine::Utils.relative_url_root = @relative_url_root
88 end
88 end
89
89
90 def test_login_should_not_redirect_to_another_host
90 def test_login_should_not_redirect_to_another_host
@@ -99,8 +99,8 class AccountControllerTest < ActionController::TestCase
99 end
99 end
100
100
101 def test_login_with_suburi_should_not_redirect_to_another_suburi
101 def test_login_with_suburi_should_not_redirect_to_another_suburi
102 @relative_url_root = ApplicationController.relative_url_root
102 @relative_url_root = Redmine::Utils.relative_url_root
103 ApplicationController.relative_url_root = '/redmine'
103 Redmine::Utils.relative_url_root = '/redmine'
104
104
105 back_urls = [
105 back_urls = [
106 'http://test.host/',
106 'http://test.host/',
@@ -115,7 +115,7 class AccountControllerTest < ActionController::TestCase
115 assert_redirected_to '/my/page'
115 assert_redirected_to '/my/page'
116 end
116 end
117 ensure
117 ensure
118 ApplicationController.relative_url_root = @relative_url_root
118 Redmine::Utils.relative_url_root = @relative_url_root
119 end
119 end
120
120
121 def test_login_with_wrong_password
121 def test_login_with_wrong_password
@@ -127,12 +127,14 class ActivitiesControllerTest < ActionController::TestCase
127 end
127 end
128
128
129 def test_index_atom_feed_with_one_item_type
129 def test_index_atom_feed_with_one_item_type
130 with_settings :default_language => 'en' do
130 get :index, :format => 'atom', :show_issues => '1'
131 get :index, :format => 'atom', :show_issues => '1'
131 assert_response :success
132 assert_response :success
132 assert_template 'common/feed'
133 assert_template 'common/feed'
133
134
134 assert_select 'title', :text => /Issues/
135 assert_select 'title', :text => /Issues/
135 end
136 end
137 end
136
138
137 def test_index_should_show_private_notes_with_permission_only
139 def test_index_should_show_private_notes_with_permission_only
138 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
140 journal = Journal.create!(:journalized => Issue.find(2), :notes => 'Private notes with searchkeyword', :private_notes => true)
@@ -139,8 +139,7 class AttachmentsControllerTest < ActionController::TestCase
139 assert a.save
139 assert a.save
140 assert_equal 'japanese-utf-8.txt', a.filename
140 assert_equal 'japanese-utf-8.txt', a.filename
141
141
142 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
142 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
143 str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding)
144
143
145 get :show, :id => a.id
144 get :show, :id => a.id
146 assert_response :success
145 assert_response :success
@@ -48,10 +48,10 class CalendarsControllerTest < ActionController::TestCase
48 end
48 end
49
49
50 def test_week_number_calculation
50 def test_week_number_calculation
51 Setting.start_of_week = 7
51 with_settings :start_of_week => 7 do
52
53 get :show, :month => '1', :year => '2010'
52 get :show, :month => '1', :year => '2010'
54 assert_response :success
53 assert_response :success
54 end
55
55
56 assert_select 'tr' do
56 assert_select 'tr' do
57 assert_select 'td.week-number', :text => '53'
57 assert_select 'td.week-number', :text => '53'
@@ -65,9 +65,10 class CalendarsControllerTest < ActionController::TestCase
65 assert_select 'td.even', :text => '9'
65 assert_select 'td.even', :text => '9'
66 end
66 end
67
67
68 Setting.start_of_week = 1
68 with_settings :start_of_week => 1 do
69 get :show, :month => '1', :year => '2010'
69 get :show, :month => '1', :year => '2010'
70 assert_response :success
70 assert_response :success
71 end
71
72
72 assert_select 'tr' do
73 assert_select 'tr' do
73 assert_select 'td.week-number', :text => '53'
74 assert_select 'td.week-number', :text => '53'
@@ -56,6 +56,7 class ContextMenusControllerTest < ActionController::TestCase
56 end
56 end
57
57
58 def test_context_menu_one_issue_by_anonymous
58 def test_context_menu_one_issue_by_anonymous
59 with_settings :default_language => 'en' do
59 get :issues, :ids => [1]
60 get :issues, :ids => [1]
60 assert_response :success
61 assert_response :success
61 assert_template 'context_menus/issues'
62 assert_template 'context_menus/issues'
@@ -63,6 +64,7 class ContextMenusControllerTest < ActionController::TestCase
63 :attributes => { :href => '#',
64 :attributes => { :href => '#',
64 :class => 'icon-del disabled' }
65 :class => 'icon-del disabled' }
65 end
66 end
67 end
66
68
67 def test_context_menu_multiple_issues_of_same_project
69 def test_context_menu_multiple_issues_of_same_project
68 @request.session[:user_id] = 2
70 @request.session[:user_id] = 2
@@ -112,7 +112,7 class CustomFieldsControllerTest < ActionController::TestCase
112 end
112 end
113
113
114 def test_new_js
114 def test_new_js
115 get :new, :type => 'IssueCustomField', :custom_field => {:field_format => 'list'}, :format => 'js'
115 xhr :get, :new, :type => 'IssueCustomField', :custom_field => {:field_format => 'list'}, :format => 'js'
116 assert_response :success
116 assert_response :success
117 assert_template 'new'
117 assert_template 'new'
118 assert_equal 'text/javascript', response.content_type
118 assert_equal 'text/javascript', response.content_type
@@ -201,7 +201,7 class GroupsControllerTest < ActionController::TestCase
201 end
201 end
202
202
203 def test_autocomplete_for_user
203 def test_autocomplete_for_user
204 get :autocomplete_for_user, :id => 10, :q => 'smi', :format => 'js'
204 xhr :get, :autocomplete_for_user, :id => 10, :q => 'smi', :format => 'js'
205 assert_response :success
205 assert_response :success
206 assert_include 'John Smith', response.body
206 assert_include 'John Smith', response.body
207 end
207 end
@@ -474,12 +474,8 class IssuesControllerTest < ActionController::TestCase
474
474
475 def test_index_csv_big_5
475 def test_index_csv_big_5
476 with_settings :default_language => "zh-TW" do
476 with_settings :default_language => "zh-TW" do
477 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
477 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
478 str_big5 = "\xa4@\xa4\xeb"
478 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
479 if str_utf8.respond_to?(:force_encoding)
480 str_utf8.force_encoding('UTF-8')
481 str_big5.force_encoding('Big5')
482 end
483 issue = Issue.generate!(:subject => str_utf8)
479 issue = Issue.generate!(:subject => str_utf8)
484
480
485 get :index, :project_id => 1,
481 get :index, :project_id => 1,
@@ -488,10 +484,7 class IssuesControllerTest < ActionController::TestCase
488 :format => 'csv'
484 :format => 'csv'
489 assert_equal 'text/csv; header=present', @response.content_type
485 assert_equal 'text/csv; header=present', @response.content_type
490 lines = @response.body.chomp.split("\n")
486 lines = @response.body.chomp.split("\n")
491 s1 = "\xaa\xac\xbaA"
487 s1 = "\xaa\xac\xbaA".force_encoding('Big5')
492 if str_utf8.respond_to?(:force_encoding)
493 s1.force_encoding('Big5')
494 end
495 assert_include s1, lines[0]
488 assert_include s1, lines[0]
496 assert_include str_big5, lines[1]
489 assert_include str_big5, lines[1]
497 end
490 end
@@ -499,10 +492,7 class IssuesControllerTest < ActionController::TestCase
499
492
500 def test_index_csv_cannot_convert_should_be_replaced_big_5
493 def test_index_csv_cannot_convert_should_be_replaced_big_5
501 with_settings :default_language => "zh-TW" do
494 with_settings :default_language => "zh-TW" do
502 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
495 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
503 if str_utf8.respond_to?(:force_encoding)
504 str_utf8.force_encoding('UTF-8')
505 end
506 issue = Issue.generate!(:subject => str_utf8)
496 issue = Issue.generate!(:subject => str_utf8)
507
497
508 get :index, :project_id => 1,
498 get :index, :project_id => 1,
@@ -513,21 +503,11 class IssuesControllerTest < ActionController::TestCase
513 :set_filter => 1
503 :set_filter => 1
514 assert_equal 'text/csv; header=present', @response.content_type
504 assert_equal 'text/csv; header=present', @response.content_type
515 lines = @response.body.chomp.split("\n")
505 lines = @response.body.chomp.split("\n")
516 s1 = "\xaa\xac\xbaA" # status
506 s1 = "\xaa\xac\xbaA".force_encoding('Big5') # status
517 if str_utf8.respond_to?(:force_encoding)
518 s1.force_encoding('Big5')
519 end
520 assert lines[0].include?(s1)
507 assert lines[0].include?(s1)
521 s2 = lines[1].split(",")[2]
508 s2 = lines[1].split(",")[2]
522 if s1.respond_to?(:force_encoding)
509 s3 = "\xa5H?".force_encoding('Big5') # subject
523 s3 = "\xa5H?" # subject
524 s3.force_encoding('Big5')
525 assert_equal s3, s2
510 assert_equal s3, s2
526 elsif RUBY_PLATFORM == 'java'
527 assert_equal "??", s2
528 else
529 assert_equal "\xa5H???", s2
530 end
531 end
511 end
532 end
512 end
533
513
@@ -3120,14 +3100,8 class IssuesControllerTest < ActionController::TestCase
3120 def test_put_update_with_attachment_that_fails_to_save
3100 def test_put_update_with_attachment_that_fails_to_save
3121 set_tmp_attachments_directory
3101 set_tmp_attachments_directory
3122
3102
3123 # Delete all fixtured journals, a race condition can occur causing the wrong
3124 # journal to get fetched in the next find.
3125 Journal.delete_all
3126
3127 # Mock out the unsaved attachment
3128 Attachment.any_instance.stubs(:create).returns(Attachment.new)
3129
3130 # anonymous user
3103 # anonymous user
3104 with_settings :attachment_max_size => 0 do
3131 put :update,
3105 put :update,
3132 :id => 1,
3106 :id => 1,
3133 :issue => {:notes => ''},
3107 :issue => {:notes => ''},
@@ -3135,6 +3109,7 class IssuesControllerTest < ActionController::TestCase
3135 assert_redirected_to :action => 'show', :id => '1'
3109 assert_redirected_to :action => 'show', :id => '1'
3136 assert_equal '1 file(s) could not be saved.', flash[:warning]
3110 assert_equal '1 file(s) could not be saved.', flash[:warning]
3137 end
3111 end
3112 end
3138
3113
3139 def test_put_update_with_no_change
3114 def test_put_update_with_no_change
3140 issue = Issue.find(1)
3115 issue = Issue.find(1)
@@ -3379,7 +3354,7 class IssuesControllerTest < ActionController::TestCase
3379 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3354 post :bulk_edit, :ids => [1, 2, 6], :issue => {:project_id => 1}
3380 assert_response :success
3355 assert_response :success
3381 assert_template 'bulk_edit'
3356 assert_template 'bulk_edit'
3382 assert_equal Project.find(1).shared_versions.open.all.sort, assigns(:versions).sort
3357 assert_equal Project.find(1).shared_versions.open.to_a.sort, assigns(:versions).sort
3383
3358
3384 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3359 assert_select 'select[name=?]', 'issue[fixed_version_id]' do
3385 assert_select 'option', :text => '2.0'
3360 assert_select 'option', :text => '2.0'
@@ -199,8 +199,8 class IssuesCustomFieldsVisibilityTest < ActionController::TestCase
199 p1 = Project.generate!
199 p1 = Project.generate!
200 p2 = Project.generate!
200 p2 = Project.generate!
201 user = User.generate!
201 user = User.generate!
202 User.add_to_project(user, p1, Role.where(:id => [1, 3]).all)
202 User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
203 User.add_to_project(user, p2, Role.where(:id => 3).all)
203 User.add_to_project(user, p2, Role.where(:id => 3).to_a)
204 Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueA'})
204 Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueA'})
205 Issue.generate!(:project => p2, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueB'})
205 Issue.generate!(:project => p2, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueB'})
206 Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueC'})
206 Issue.generate!(:project => p1, :tracker_id => 1, :custom_field_values => {@field2.id => 'ValueC'})
@@ -104,7 +104,7 class MembersControllerTest < ActionController::TestCase
104 end
104 end
105
105
106 def test_autocomplete
106 def test_autocomplete
107 get :autocomplete, :project_id => 1, :q => 'mis', :format => 'js'
107 xhr :get, :autocomplete, :project_id => 1, :q => 'mis', :format => 'js'
108 assert_response :success
108 assert_response :success
109 assert_include 'User Misc', response.body
109 assert_include 'User Misc', response.body
110 end
110 end
@@ -59,8 +59,8 class MessagesControllerTest < ActionController::TestCase
59 assert_template 'show'
59 assert_template 'show'
60 replies = assigns(:replies)
60 replies = assigns(:replies)
61 assert_not_nil replies
61 assert_not_nil replies
62 assert !replies.include?(message.children.order('id').first)
62 assert_not_include message.children.reorder('id').first, replies
63 assert replies.include?(message.children.order('id').last)
63 assert_include message.children.reorder('id').last, replies
64 end
64 end
65
65
66 def test_show_with_reply_permission
66 def test_show_with_reply_permission
@@ -167,7 +167,7 class MyControllerTest < ActionController::TestCase
167 :new_password_confirmation => 'secret1234'
167 :new_password_confirmation => 'secret1234'
168 assert_response :success
168 assert_response :success
169 assert_template 'password'
169 assert_template 'password'
170 assert_error_tag :content => /Password doesn&#x27;t match confirmation/
170 assert_error_tag :content => /Password doesn.*t match confirmation/
171
171
172 # wrong password
172 # wrong password
173 post :password, :password => 'wrongpassword',
173 post :password, :password => 'wrongpassword',
@@ -26,7 +26,7 class RepositoriesBazaarControllerTest < ActionController::TestCase
26 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
26 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
27 REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
27 REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
28 PRJ_ID = 3
28 PRJ_ID = 3
29 CHAR_1_UTF8_HEX = "\xc3\x9c"
29 CHAR_1_UTF8_HEX = "\xc3\x9c".dup.force_encoding('UTF-8')
30
30
31 def setup
31 def setup
32 User.current = nil
32 User.current = nil
@@ -36,10 +36,6 class RepositoriesBazaarControllerTest < ActionController::TestCase
36 :url => REPOSITORY_PATH_TRUNK,
36 :url => REPOSITORY_PATH_TRUNK,
37 :log_encoding => 'UTF-8')
37 :log_encoding => 'UTF-8')
38 assert @repository
38 assert @repository
39 @char_1_utf8 = CHAR_1_UTF8_HEX.dup
40 if @char_1_utf8.respond_to?(:force_encoding)
41 @char_1_utf8.force_encoding('UTF-8')
42 end
43 end
39 end
44
40
45 if File.directory?(REPOSITORY_PATH)
41 if File.directory?(REPOSITORY_PATH)
@@ -176,7 +172,6 class RepositoriesBazaarControllerTest < ActionController::TestCase
176 end
172 end
177 end
173 end
178
174
179 if REPOSITORY_PATH.respond_to?(:force_encoding)
180 def test_annotate_author_non_ascii
175 def test_annotate_author_non_ascii
181 log_encoding = nil
176 log_encoding = nil
182 if Encoding.locale_charmap == "UTF-8" ||
177 if Encoding.locale_charmap == "UTF-8" ||
@@ -197,7 +192,7 class RepositoriesBazaarControllerTest < ActionController::TestCase
197 assert_select "th.line-num", :text => '1' do
192 assert_select "th.line-num", :text => '1' do
198 assert_select "+ td.revision" do
193 assert_select "+ td.revision" do
199 assert_select "a", :text => '2'
194 assert_select "a", :text => '2'
200 assert_select "+ td.author", :text => "test #{@char_1_utf8}" do
195 assert_select "+ td.author", :text => "test #{CHAR_1_UTF8_HEX}" do
201 assert_select "+ td",
196 assert_select "+ td",
202 :text => "author non ASCII test"
197 :text => "author non ASCII test"
203 end
198 end
@@ -205,7 +200,6 class RepositoriesBazaarControllerTest < ActionController::TestCase
205 end
200 end
206 end
201 end
207 end
202 end
208 end
209
203
210 def test_destroy_valid_repository
204 def test_destroy_valid_repository
211 @request.session[:user_id] = 1 # admin
205 @request.session[:user_id] = 1 # admin
@@ -27,8 +27,7 class RepositoriesFilesystemControllerTest < ActionController::TestCase
27 PRJ_ID = 3
27 PRJ_ID = 3
28
28
29 def setup
29 def setup
30 @ruby19_non_utf8_pass =
30 @ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
31 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
32 User.current = nil
31 User.current = nil
33 Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
32 Setting.enabled_scm << 'Filesystem' unless Setting.enabled_scm.include?('Filesystem')
34 @project = Project.find(PRJ_ID)
33 @project = Project.find(PRJ_ID)
@@ -94,12 +93,11 class RepositoriesFilesystemControllerTest < ActionController::TestCase
94 :attributes => { :class => 'line-num' },
93 :attributes => { :class => 'line-num' },
95 :sibling => { :tag => 'td', :content => /japanese/ }
94 :sibling => { :tag => 'td', :content => /japanese/ }
96 if @ruby19_non_utf8_pass
95 if @ruby19_non_utf8_pass
97 puts "TODO: show repository file contents test fails in Ruby 1.9 " +
96 puts "TODO: show repository file contents test fails " +
98 "and Encoding.default_external is not UTF-8. " +
97 "when Encoding.default_external is not UTF-8. " +
99 "Current value is '#{Encoding.default_external.to_s}'"
98 "Current value is '#{Encoding.default_external.to_s}'"
100 else
99 else
101 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
100 str_japanese = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
102 str_japanese.force_encoding('UTF-8') if str_japanese.respond_to?(:force_encoding)
103 assert_tag :tag => 'th',
101 assert_tag :tag => 'th',
104 :content => '3',
102 :content => '3',
105 :attributes => { :class => 'line-num' },
103 :attributes => { :class => 'line-num' },
@@ -109,7 +107,7 class RepositoriesFilesystemControllerTest < ActionController::TestCase
109 end
107 end
110
108
111 def test_show_utf16
109 def test_show_utf16
112 enc = (RUBY_VERSION == "1.9.2" ? 'UTF-16LE' : 'UTF-16')
110 enc = 'UTF-16'
113 with_settings :repositories_encodings => enc do
111 with_settings :repositories_encodings => enc do
114 get :entry, :id => PRJ_ID,
112 get :entry, :id => PRJ_ID,
115 :path => repository_path_hash(['japanese', 'utf-16.txt'])[:param]
113 :path => repository_path_hash(['japanese', 'utf-16.txt'])[:param]
@@ -26,8 +26,8 class RepositoriesGitControllerTest < ActionController::TestCase
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
26 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
28 PRJ_ID = 3
28 PRJ_ID = 3
29 CHAR_1_HEX = "\xc3\x9c"
29 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
30 FELIX_HEX = "Felix Sch\xC3\xA4fer"
30 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
31 NUM_REV = 28
31 NUM_REV = 28
32
32
33 ## Git, Mercurial and CVS path encodings are binary.
33 ## Git, Mercurial and CVS path encodings are binary.
@@ -39,8 +39,7 class RepositoriesGitControllerTest < ActionController::TestCase
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
39 JRUBY_SKIP_STR = "TODO: This test fails in JRuby"
40
40
41 def setup
41 def setup
42 @ruby19_non_utf8_pass =
42 @ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
43 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
44
43
45 User.current = nil
44 User.current = nil
46 @project = Project.find(PRJ_ID)
45 @project = Project.find(PRJ_ID)
@@ -50,12 +49,6 class RepositoriesGitControllerTest < ActionController::TestCase
50 :path_encoding => 'ISO-8859-1'
49 :path_encoding => 'ISO-8859-1'
51 )
50 )
52 assert @repository
51 assert @repository
53 @char_1 = CHAR_1_HEX.dup
54 @felix_utf8 = FELIX_HEX.dup
55 if @char_1.respond_to?(:force_encoding)
56 @char_1.force_encoding('UTF-8')
57 @felix_utf8.force_encoding('UTF-8')
58 end
59 end
52 end
60
53
61 def test_create_and_update
54 def test_create_and_update
@@ -231,7 +224,7 class RepositoriesGitControllerTest < ActionController::TestCase
231 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
224 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
232 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
225 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
233 get :entry, :id => PRJ_ID,
226 get :entry, :id => PRJ_ID,
234 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
227 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
235 :rev => r1
228 :rev => r1
236 assert_response :success
229 assert_response :success
237 assert_template 'entry'
230 assert_template 'entry'
@@ -239,7 +232,7 class RepositoriesGitControllerTest < ActionController::TestCase
239 :content => '1',
232 :content => '1',
240 :attributes => { :class => 'line-num' },
233 :attributes => { :class => 'line-num' },
241 :sibling => { :tag => 'td',
234 :sibling => { :tag => 'td',
242 :content => /test-#{@char_1}.txt/ }
235 :content => /test-#{CHAR_1_HEX}.txt/ }
243 end
236 end
244 end
237 end
245 end
238 end
@@ -419,14 +412,14 class RepositoriesGitControllerTest < ActionController::TestCase
419 :descendant => {
412 :descendant => {
420 :tag => 'th',
413 :tag => 'th',
421 :attributes => { :class => 'filename' } ,
414 :attributes => { :class => 'filename' } ,
422 :content => /latin-1-dir\/test-#{@char_1}.txt/ ,
415 :content => /latin-1-dir\/test-#{CHAR_1_HEX}.txt/ ,
423 },
416 },
424 :sibling => {
417 :sibling => {
425 :tag => 'tbody',
418 :tag => 'tbody',
426 :descendant => {
419 :descendant => {
427 :tag => 'td',
420 :tag => 'td',
428 :attributes => { :class => /diff_in/ },
421 :attributes => { :class => /diff_in/ },
429 :content => /test-#{@char_1}.txt/
422 :content => /test-#{CHAR_1_HEX}.txt/
430 }
423 }
431 }
424 }
432 end
425 end
@@ -498,12 +491,14 class RepositoriesGitControllerTest < ActionController::TestCase
498 end
491 end
499
492
500 def test_annotate_binary_file
493 def test_annotate_binary_file
494 with_settings :default_language => 'en' do
501 get :annotate, :id => PRJ_ID,
495 get :annotate, :id => PRJ_ID,
502 :path => repository_path_hash(['images', 'edit.png'])[:param]
496 :path => repository_path_hash(['images', 'edit.png'])[:param]
503 assert_response 500
497 assert_response 500
504 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
498 assert_tag :tag => 'p', :attributes => { :id => /errorExplanation/ },
505 :content => /cannot be annotated/
499 :content => /cannot be annotated/
506 end
500 end
501 end
507
502
508 def test_annotate_error_when_too_big
503 def test_annotate_error_when_too_big
509 with_settings :file_max_size_displayed => 1 do
504 with_settings :file_max_size_displayed => 1 do
@@ -533,14 +528,14 class RepositoriesGitControllerTest < ActionController::TestCase
533 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
528 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
534 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
529 ['57ca437c', '57ca437c0acbbcb749821fdf3726a1367056d364'].each do |r1|
535 get :annotate, :id => PRJ_ID,
530 get :annotate, :id => PRJ_ID,
536 :path => repository_path_hash(['latin-1-dir', "test-#{@char_1}.txt"])[:param],
531 :path => repository_path_hash(['latin-1-dir', "test-#{CHAR_1_HEX}.txt"])[:param],
537 :rev => r1
532 :rev => r1
538 assert_select "th.line-num", :text => '1' do
533 assert_select "th.line-num", :text => '1' do
539 assert_select "+ td.revision" do
534 assert_select "+ td.revision" do
540 assert_select "a", :text => '57ca437c'
535 assert_select "a", :text => '57ca437c'
541 assert_select "+ td.author", :text => "jsmith" do
536 assert_select "+ td.author", :text => "jsmith" do
542 assert_select "+ td",
537 assert_select "+ td",
543 :text => "test-#{@char_1}.txt"
538 :text => "test-#{CHAR_1_HEX}.txt"
544 end
539 end
545 end
540 end
546 end
541 end
@@ -557,7 +552,7 class RepositoriesGitControllerTest < ActionController::TestCase
557 assert_select "th.line-num", :text => '1' do
552 assert_select "th.line-num", :text => '1' do
558 assert_select "+ td.revision" do
553 assert_select "+ td.revision" do
559 assert_select "a", :text => '83ca5fd5'
554 assert_select "a", :text => '83ca5fd5'
560 assert_select "+ td.author", :text => @felix_utf8 do
555 assert_select "+ td.author", :text => FELIX_HEX do
561 assert_select "+ td",
556 assert_select "+ td",
562 :text => "And this is a file with a leading and trailing space..."
557 :text => "And this is a file with a leading and trailing space..."
563 end
558 end
@@ -643,8 +638,8 class RepositoriesGitControllerTest < ActionController::TestCase
643 private
638 private
644
639
645 def puts_ruby19_non_utf8_pass
640 def puts_ruby19_non_utf8_pass
646 puts "TODO: This test fails in Ruby 1.9 " +
641 puts "TODO: This test fails " +
647 "and Encoding.default_external is not UTF-8. " +
642 "when Encoding.default_external is not UTF-8. " +
648 "Current value is '#{Encoding.default_external.to_s}'"
643 "Current value is '#{Encoding.default_external.to_s}'"
649 end
644 end
650 else
645 else
@@ -28,8 +28,7 class RepositoriesMercurialControllerTest < ActionController::TestCase
28 PRJ_ID = 3
28 PRJ_ID = 3
29 NUM_REV = 34
29 NUM_REV = 34
30
30
31 ruby19_non_utf8_pass =
31 ruby19_non_utf8_pass = Encoding.default_external.to_s != 'UTF-8'
32 (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8')
33
32
34 def setup
33 def setup
35 User.current = nil
34 User.current = nil
@@ -41,21 +40,15 class RepositoriesMercurialControllerTest < ActionController::TestCase
41 )
40 )
42 assert @repository
41 assert @repository
43 @diff_c_support = true
42 @diff_c_support = true
44 @char_1 = CHAR_1_HEX.dup
43 @char_1 = CHAR_1_HEX.dup.force_encoding('UTF-8')
45 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
44 @tag_char_1 = "tag-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
46 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
45 @branch_char_0 = "branch-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
47 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
46 @branch_char_1 = "branch-#{CHAR_1_HEX}-01".force_encoding('UTF-8')
48 if @char_1.respond_to?(:force_encoding)
49 @char_1.force_encoding('UTF-8')
50 @tag_char_1.force_encoding('UTF-8')
51 @branch_char_0.force_encoding('UTF-8')
52 @branch_char_1.force_encoding('UTF-8')
53 end
54 end
47 end
55
48
56 if ruby19_non_utf8_pass
49 if ruby19_non_utf8_pass
57 puts "TODO: Mercurial functional test fails in Ruby 1.9 " +
50 puts "TODO: Mercurial functional test fails " +
58 "and Encoding.default_external is not UTF-8. " +
51 "when Encoding.default_external is not UTF-8. " +
59 "Current value is '#{Encoding.default_external.to_s}'"
52 "Current value is '#{Encoding.default_external.to_s}'"
60 def test_fake; assert true end
53 def test_fake; assert true end
61 elsif File.directory?(REPOSITORY_PATH)
54 elsif File.directory?(REPOSITORY_PATH)
@@ -31,7 +31,7 class RolesControllerTest < ActionController::TestCase
31 assert_template 'index'
31 assert_template 'index'
32
32
33 assert_not_nil assigns(:roles)
33 assert_not_nil assigns(:roles)
34 assert_equal Role.order('builtin, position').all, assigns(:roles)
34 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
35
35
36 assert_tag :tag => 'a', :attributes => { :href => '/roles/1/edit' },
36 assert_tag :tag => 'a', :attributes => { :href => '/roles/1/edit' },
37 :content => 'Manager'
37 :content => 'Manager'
@@ -160,7 +160,7 class RolesControllerTest < ActionController::TestCase
160 assert_template 'permissions'
160 assert_template 'permissions'
161
161
162 assert_not_nil assigns(:roles)
162 assert_not_nil assigns(:roles)
163 assert_equal Role.order('builtin, position').all, assigns(:roles)
163 assert_equal Role.order('builtin, position').to_a, assigns(:roles)
164
164
165 assert_tag :tag => 'input', :attributes => { :type => 'checkbox',
165 assert_tag :tag => 'input', :attributes => { :type => 'checkbox',
166 :name => 'permissions[3][]',
166 :name => 'permissions[3][]',
@@ -40,7 +40,9 class SearchControllerTest < ActionController::TestCase
40 end
40 end
41
41
42 def test_search_all_projects
42 def test_search_all_projects
43 with_settings :default_language => 'en' do
43 get :index, :q => 'recipe subproject commit', :all_words => ''
44 get :index, :q => 'recipe subproject commit', :all_words => ''
45 end
44 assert_response :success
46 assert_response :success
45 assert_template 'index'
47 assert_template 'index'
46
48
@@ -240,12 +240,8 class TimeEntryReportsControllerTest < ActionController::TestCase
240
240
241 def test_csv_big_5
241 def test_csv_big_5
242 Setting.default_language = "zh-TW"
242 Setting.default_language = "zh-TW"
243 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88"
243 str_utf8 = "\xe4\xb8\x80\xe6\x9c\x88".force_encoding('UTF-8')
244 str_big5 = "\xa4@\xa4\xeb"
244 str_big5 = "\xa4@\xa4\xeb".force_encoding('Big5')
245 if str_utf8.respond_to?(:force_encoding)
246 str_utf8.force_encoding('UTF-8')
247 str_big5.force_encoding('Big5')
248 end
249 user = User.find_by_id(3)
245 user = User.find_by_id(3)
250 user.firstname = str_utf8
246 user.firstname = str_utf8
251 user.lastname = "test-lastname"
247 user.lastname = "test-lastname"
@@ -270,21 +266,14 class TimeEntryReportsControllerTest < ActionController::TestCase
270 assert_equal 'text/csv; header=present', @response.content_type
266 assert_equal 'text/csv; header=present', @response.content_type
271 lines = @response.body.chomp.split("\n")
267 lines = @response.body.chomp.split("\n")
272 # Headers
268 # Headers
273 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp"
269 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
274 s2 = "\xa4u\xae\xc9\xc1`\xadp"
270 s2 = "\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
275 if s1.respond_to?(:force_encoding)
276 s1.force_encoding('Big5')
277 s2.force_encoding('Big5')
278 end
279 assert_equal s1, lines.first
271 assert_equal s1, lines.first
280 # Total row
272 # Total row
281 assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1]
273 assert_equal "#{str_big5} #{user.lastname},7.30,7.30", lines[1]
282 assert_equal "#{s2},7.30,7.30", lines[2]
274 assert_equal "#{s2},7.30,7.30", lines[2]
283
275
284 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
276 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)".force_encoding('UTF-8')
285 if str_tw.respond_to?(:force_encoding)
286 str_tw.force_encoding('UTF-8')
287 end
288 assert_equal str_tw, l(:general_lang_name)
277 assert_equal str_tw, l(:general_lang_name)
289 assert_equal 'Big5', l(:general_csv_encoding)
278 assert_equal 'Big5', l(:general_csv_encoding)
290 assert_equal ',', l(:general_csv_separator)
279 assert_equal ',', l(:general_csv_separator)
@@ -293,10 +282,7 class TimeEntryReportsControllerTest < ActionController::TestCase
293
282
294 def test_csv_cannot_convert_should_be_replaced_big_5
283 def test_csv_cannot_convert_should_be_replaced_big_5
295 Setting.default_language = "zh-TW"
284 Setting.default_language = "zh-TW"
296 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85"
285 str_utf8 = "\xe4\xbb\xa5\xe5\x86\x85".force_encoding('UTF-8')
297 if str_utf8.respond_to?(:force_encoding)
298 str_utf8.force_encoding('UTF-8')
299 end
300 user = User.find_by_id(3)
286 user = User.find_by_id(3)
301 user.firstname = str_utf8
287 user.firstname = str_utf8
302 user.lastname = "test-lastname"
288 user.lastname = "test-lastname"
@@ -321,21 +307,10 class TimeEntryReportsControllerTest < ActionController::TestCase
321 assert_equal 'text/csv; header=present', @response.content_type
307 assert_equal 'text/csv; header=present', @response.content_type
322 lines = @response.body.chomp.split("\n")
308 lines = @response.body.chomp.split("\n")
323 # Headers
309 # Headers
324 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp"
310 s1 = "\xa5\xce\xa4\xe1,2011-11-11,\xa4u\xae\xc9\xc1`\xadp".force_encoding('Big5')
325 if s1.respond_to?(:force_encoding)
326 s1.force_encoding('Big5')
327 end
328 assert_equal s1, lines.first
311 assert_equal s1, lines.first
329 # Total row
312 # Total row
330 s2 = ""
313 s2 = "\xa5H?".force_encoding('Big5')
331 if s2.respond_to?(:force_encoding)
332 s2 = "\xa5H?"
333 s2.force_encoding('Big5')
334 elsif RUBY_PLATFORM == 'java'
335 s2 = "??"
336 else
337 s2 = "\xa5H???"
338 end
339 assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1]
314 assert_equal "#{s2} #{user.lastname},7.30,7.30", lines[1]
340 end
315 end
341
316
@@ -362,21 +337,14 class TimeEntryReportsControllerTest < ActionController::TestCase
362 assert_equal 'text/csv; header=present', @response.content_type
337 assert_equal 'text/csv; header=present', @response.content_type
363 lines = @response.body.chomp.split("\n")
338 lines = @response.body.chomp.split("\n")
364 # Headers
339 # Headers
365 s1 = "Utilisateur;2011-11-11;Temps total"
340 s1 = "Utilisateur;2011-11-11;Temps total".force_encoding('ISO-8859-1')
366 s2 = "Temps total"
341 s2 = "Temps total".force_encoding('ISO-8859-1')
367 if s1.respond_to?(:force_encoding)
368 s1.force_encoding('ISO-8859-1')
369 s2.force_encoding('ISO-8859-1')
370 end
371 assert_equal s1, lines.first
342 assert_equal s1, lines.first
372 # Total row
343 # Total row
373 assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1]
344 assert_equal "#{user.firstname} #{user.lastname};7,30;7,30", lines[1]
374 assert_equal "#{s2};7,30;7,30", lines[2]
345 assert_equal "#{s2};7,30;7,30", lines[2]
375
346
376 str_fr = "Fran\xc3\xa7ais"
347 str_fr = "Fran\xc3\xa7ais".force_encoding('UTF-8')
377 if str_fr.respond_to?(:force_encoding)
378 str_fr.force_encoding('UTF-8')
379 end
380 assert_equal str_fr, l(:general_lang_name)
348 assert_equal str_fr, l(:general_lang_name)
381 assert_equal 'ISO-8859-1', l(:general_csv_encoding)
349 assert_equal 'ISO-8859-1', l(:general_csv_encoding)
382 assert_equal ';', l(:general_csv_separator)
350 assert_equal ';', l(:general_csv_separator)
@@ -702,16 +702,18 class TimelogControllerTest < ActionController::TestCase
702 end
702 end
703
703
704 def test_index_csv_all_projects
704 def test_index_csv_all_projects
705 Setting.date_format = '%m/%d/%Y'
705 with_settings :date_format => '%m/%d/%Y' do
706 get :index, :format => 'csv'
706 get :index, :format => 'csv'
707 assert_response :success
707 assert_response :success
708 assert_equal 'text/csv; header=present', response.content_type
708 assert_equal 'text/csv; header=present', response.content_type
709 end
709 end
710 end
710
711
711 def test_index_csv
712 def test_index_csv
712 Setting.date_format = '%m/%d/%Y'
713 with_settings :date_format => '%m/%d/%Y' do
713 get :index, :project_id => 1, :format => 'csv'
714 get :index, :project_id => 1, :format => 'csv'
714 assert_response :success
715 assert_response :success
715 assert_equal 'text/csv; header=present', response.content_type
716 assert_equal 'text/csv; header=present', response.content_type
716 end
717 end
717 end
718 end
719 end
@@ -95,8 +95,8 class TimelogCustomFieldsVisibilityTest < ActionController::TestCase
95 p1 = Project.generate!
95 p1 = Project.generate!
96 p2 = Project.generate!
96 p2 = Project.generate!
97 user = User.generate!
97 user = User.generate!
98 User.add_to_project(user, p1, Role.where(:id => [1, 3]).all)
98 User.add_to_project(user, p1, Role.where(:id => [1, 3]).to_a)
99 User.add_to_project(user, p2, Role.where(:id => 3).all)
99 User.add_to_project(user, p2, Role.where(:id => 3).to_a)
100 TimeEntry.generate!(
100 TimeEntry.generate!(
101 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
101 :issue => Issue.generate!(:project => p1, :tracker_id => 1,
102 :custom_field_values => {@field2.id => 'ValueA'}))
102 :custom_field_values => {@field2.id => 'ValueA'}))
@@ -108,9 +108,9 class TimelogCustomFieldsVisibilityTest < ActionController::TestCase
108 :custom_field_values => {@field2.id => 'ValueC'}))
108 :custom_field_values => {@field2.id => 'ValueC'}))
109 @request.session[:user_id] = user.id
109 @request.session[:user_id] = user.id
110 get :index, :c => ["hours", "issue.cf_#{@field2.id}"]
110 get :index, :c => ["hours", "issue.cf_#{@field2.id}"]
111 assert_select 'td', :text => 'ValueA'
111 assert_select 'td', {:text => 'ValueA'}, "ValueA not found in:\n#{response.body}"
112 assert_select 'td', :text => 'ValueB', :count => 0
112 assert_select 'td', :text => 'ValueB', :count => 0
113 assert_select 'td', :text => 'ValueC'
113 assert_select 'td', {:text => 'ValueC'}, "ValueC not found in:\n#{response.body}"
114
114
115 get :index, :set_filter => '1', "issue.cf_#{@field2.id}" => '*'
115 get :index, :set_filter => '1', "issue.cf_#{@field2.id}" => '*'
116 assert_equal %w(ValueA ValueC), assigns(:entries).map{|i| i.issue.custom_field_value(@field2)}.sort
116 assert_equal %w(ValueA ValueC), assigns(:entries).map{|i| i.issue.custom_field_value(@field2)}.sort
@@ -97,9 +97,7 class WelcomeControllerTest < ActionController::TestCase
97 @request.session[:user_id] = 2
97 @request.session[:user_id] = 2
98
98
99 get :index
99 get :index
100 assert_tag 'script',
100 assert_select 'script', :text => %r{warnLeavingUnsaved}
101 :attributes => {:type => "text/javascript"},
102 :content => %r{warnLeavingUnsaved}
103 end
101 end
104
102
105 def test_warn_on_leaving_unsaved_turn_off
103 def test_warn_on_leaving_unsaved_turn_off
@@ -58,7 +58,9 class WikiControllerTest < ActionController::TestCase
58 end
58 end
59
59
60 def test_show_old_version
60 def test_show_old_version
61 with_settings :default_language => 'en' do
61 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
62 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '2'
63 end
62 assert_response :success
64 assert_response :success
63 assert_template 'show'
65 assert_template 'show'
64
66
@@ -89,7 +91,9 class WikiControllerTest < ActionController::TestCase
89 end
91 end
90
92
91 def test_show_first_version
93 def test_show_first_version
94 with_settings :default_language => 'en' do
92 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'
95 get :show, :project_id => 'ecookbook', :id => 'CookBook_documentation', :version => '1'
96 end
93 assert_response :success
97 assert_response :success
94 assert_template 'show'
98 assert_template 'show'
95
99
@@ -248,7 +248,7 class WorkflowsControllerTest < ActionController::TestCase
248
248
249 get :permissions, :role_id => 1, :tracker_id => 2, :used_statuses_only => '0'
249 get :permissions, :role_id => 1, :tracker_id => 2, :used_statuses_only => '0'
250 assert_response :success
250 assert_response :success
251 assert_equal IssueStatus.sorted.all, assigns(:statuses)
251 assert_equal IssueStatus.sorted.to_a, assigns(:statuses)
252 end
252 end
253
253
254 def test_post_permissions
254 def test_post_permissions
@@ -17,13 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 begin
20 class AccountTest < ActionDispatch::IntegrationTest
21 require 'mocha/setup'
22 rescue
23 # Won't run some tests
24 end
25
26 class AccountTest < ActionController::IntegrationTest
27 fixtures :users, :roles
21 fixtures :users, :roles
28
22
29 def test_login
23 def test_login
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class AdminTest < ActionController::IntegrationTest
20 class AdminTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :enumerations, :users, :issue_categories,
22 :enumerations, :users, :issue_categories,
23 :projects_trackers,
23 :projects_trackers,
@@ -41,11 +41,8 class Redmine::ApiTest::AuthenticationTest < Redmine::ApiTest::Base
41 end
41 end
42
42
43 def test_invalid_utf8_credentials_should_not_trigger_an_error
43 def test_invalid_utf8_credentials_should_not_trigger_an_error
44 invalid_utf8 = "\x82"
44 invalid_utf8 = "\x82".force_encoding('UTF-8')
45 if invalid_utf8.respond_to?(:force_encoding)
46 invalid_utf8.force_encoding('UTF-8')
47 assert !invalid_utf8.valid_encoding?
45 assert !invalid_utf8.valid_encoding?
48 end
49 assert_nothing_raised do
46 assert_nothing_raised do
50 get '/users/current.xml', {}, credentials(invalid_utf8, "foo")
47 get '/users/current.xml', {}, credentials(invalid_utf8, "foo")
51 end
48 end
@@ -165,7 +165,7 class Redmine::ApiTest::MembershipsTest < Redmine::ApiTest::Base
165
165
166 assert_response :unprocessable_entity
166 assert_response :unprocessable_entity
167 assert_equal 'application/xml', @response.content_type
167 assert_equal 'application/xml', @response.content_type
168 assert_tag 'errors', :child => {:tag => 'error', :content => /member_roles is invalid/}
168 assert_tag 'errors', :child => {:tag => 'error', :content => /role can't be empty/i}
169 end
169 end
170
170
171 test "DELETE /memberships/:id.xml should destroy the membership" do
171 test "DELETE /memberships/:id.xml should destroy the membership" do
@@ -195,13 +195,13 class Redmine::ApiTest::ProjectsTest < Redmine::ApiTest::Base
195 end
195 end
196
196
197 test "POST /projects.xml with valid parameters should create the project" do
197 test "POST /projects.xml with valid parameters should create the project" do
198 Setting.default_projects_modules = ['issue_tracking', 'repository']
198 with_settings :default_projects_modules => ['issue_tracking', 'repository'] do
199
200 assert_difference('Project.count') do
199 assert_difference('Project.count') do
201 post '/projects.xml',
200 post '/projects.xml',
202 {:project => {:name => 'API test', :identifier => 'api-test'}},
201 {:project => {:name => 'API test', :identifier => 'api-test'}},
203 credentials('admin')
202 credentials('admin')
204 end
203 end
204 end
205
205
206 project = Project.order('id DESC').first
206 project = Project.order('id DESC').first
207 assert_equal 'API test', project.name
207 assert_equal 'API test', project.name
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class ApplicationTest < ActionController::IntegrationTest
20 class ApplicationTest < ActionDispatch::IntegrationTest
21 include Redmine::I18n
21 include Redmine::I18n
22
22
23 fixtures :projects, :trackers, :issue_statuses, :issues,
23 fixtures :projects, :trackers, :issue_statuses, :issues,
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class AttachmentsTest < ActionController::IntegrationTest
20 class AttachmentsTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :enabled_modules,
21 fixtures :projects, :enabled_modules,
22 :users, :roles, :members, :member_roles,
22 :users, :roles, :members, :member_roles,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class FeedsTest < ActionController::IntegrationTest
20 class FeedsTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :enumerations, :users, :issue_categories,
22 :enumerations, :users, :issue_categories,
23 :projects_trackers, :enabled_modules,
23 :projects_trackers, :enabled_modules,
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class IssuesTest < ActionController::IntegrationTest
20 class IssuesTest < ActionDispatch::IntegrationTest
21 fixtures :projects,
21 fixtures :projects,
22 :users,
22 :users,
23 :roles,
23 :roles,
@@ -132,27 +132,27 class IssuesTest < ActionController::IntegrationTest
132 end
132 end
133
133
134 def test_pagination_links_on_index
134 def test_pagination_links_on_index
135 Setting.per_page_options = '2'
135 with_settings :per_page_options => '2' do
136 get '/projects/ecookbook/issues'
136 get '/projects/ecookbook/issues'
137
137
138 assert_tag :a, :content => '2',
138 assert_tag :a, :content => '2',
139 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
139 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
140
140 end
141 end
141 end
142
142
143 def test_pagination_links_on_index_without_project_id_in_url
143 def test_pagination_links_on_index_without_project_id_in_url
144 Setting.per_page_options = '2'
144 with_settings :per_page_options => '2' do
145 get '/issues', :project_id => 'ecookbook'
145 get '/issues', :project_id => 'ecookbook'
146
146
147 assert_tag :a, :content => '2',
147 assert_tag :a, :content => '2',
148 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
148 :attributes => { :href => '/projects/ecookbook/issues?page=2' }
149
149 end
150 end
150 end
151
151
152 def test_issue_with_user_custom_field
152 def test_issue_with_user_custom_field
153 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
153 @field = IssueCustomField.create!(:name => 'Tester', :field_format => 'user', :is_for_all => true, :trackers => Tracker.all)
154 Role.anonymous.add_permission! :add_issues, :edit_issues
154 Role.anonymous.add_permission! :add_issues, :edit_issues
155 users = Project.find(1).users
155 users = Project.find(1).users.uniq.sort
156 tester = users.first
156 tester = users.first
157
157
158 # Issue form
158 # Issue form
@@ -205,8 +205,8 class IssuesTest < ActionController::IntegrationTest
205 :issue => {
205 :issue => {
206 :custom_field_values => {@field.id.to_s => new_tester.id.to_s}
206 :custom_field_values => {@field.id.to_s => new_tester.id.to_s}
207 }
207 }
208 assert_redirected_to "/issues/#{issue.id}"
208 end
209 end
209 assert_response 302
210
210
211 # Issue view
211 # Issue view
212 follow_redirect!
212 follow_redirect!
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class LayoutTest < ActionController::IntegrationTest
20 class LayoutTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :trackers, :issue_statuses, :issues,
21 fixtures :projects, :trackers, :issue_statuses, :issues,
22 :enumerations, :users, :issue_categories,
22 :enumerations, :users, :issue_categories,
23 :projects_trackers,
23 :projects_trackers,
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../test_helper', __FILE__)
19
19
20 class HookTest < ActionController::IntegrationTest
20 class HookTest < ActionDispatch::IntegrationTest
21 fixtures :users, :roles, :projects, :members, :member_roles
21 fixtures :users, :roles, :projects, :members, :member_roles
22
22
23 # Hooks that are manually registered later
23 # Hooks that are manually registered later
@@ -34,6 +34,8 class HookTest < ActionController::IntegrationTest
34 end
34 end
35 end
35 end
36
36
37 Redmine::Hook.clear_listeners
38
37 class ContentForInsideHook < Redmine::Hook::ViewListener
39 class ContentForInsideHook < Redmine::Hook::ViewListener
38 render_on :view_welcome_index_left, :inline => <<-VIEW
40 render_on :view_welcome_index_left, :inline => <<-VIEW
39 <% content_for :header_tags do %>
41 <% content_for :header_tags do %>
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../test_helper', __FILE__)
19
19
20 class MenuManagerTest < ActionController::IntegrationTest
20 class MenuManagerTest < ActionDispatch::IntegrationTest
21 include Redmine::I18n
21 include Redmine::I18n
22
22
23 fixtures :projects, :trackers, :issue_statuses, :issues,
23 fixtures :projects, :trackers, :issue_statuses, :issues,
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../test_helper', __FILE__)
19
19
20 class ThemesTest < ActionController::IntegrationTest
20 class ThemesTest < ActionDispatch::IntegrationTest
21
21
22 def setup
22 def setup
23 @theme = Redmine::Themes.themes.last
23 @theme = Redmine::Themes.themes.last
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class ProjectsTest < ActionController::IntegrationTest
20 class ProjectsTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :users, :members, :enabled_modules
21 fixtures :projects, :users, :members, :enabled_modules
22
22
23 def test_archive_project
23 def test_archive_project
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class RepositoriesGitTest < ActionController::IntegrationTest
20 class RepositoriesGitTest < ActionDispatch::IntegrationTest
21 fixtures :projects, :users, :roles, :members, :member_roles,
21 fixtures :projects, :users, :roles, :members, :member_roles,
22 :repositories, :enabled_modules
22 :repositories, :enabled_modules
23
23
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingAccountTest < ActionController::IntegrationTest
20 class RoutingAccountTest < ActionDispatch::IntegrationTest
21 def test_account
21 def test_account
22 ["get", "post"].each do |method|
22 ["get", "post"].each do |method|
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingActivitiesTest < ActionController::IntegrationTest
20 class RoutingActivitiesTest < ActionDispatch::IntegrationTest
21 def test_activities
21 def test_activities
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/activity" },
23 { :method => 'get', :path => "/activity" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingAdminTest < ActionController::IntegrationTest
20 class RoutingAdminTest < ActionDispatch::IntegrationTest
21 def test_administration_panel
21 def test_administration_panel
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/admin" },
23 { :method => 'get', :path => "/admin" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingAttachmentsTest < ActionController::IntegrationTest
20 class RoutingAttachmentsTest < ActionDispatch::IntegrationTest
21 def test_attachments
21 def test_attachments
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/attachments/1" },
23 { :method => 'get', :path => "/attachments/1" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingAuthSourcesTest < ActionController::IntegrationTest
20 class RoutingAuthSourcesTest < ActionDispatch::IntegrationTest
21 def test_auth_sources
21 def test_auth_sources
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/auth_sources" },
23 { :method => 'get', :path => "/auth_sources" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingAutoCompletesTest < ActionController::IntegrationTest
20 class RoutingAutoCompletesTest < ActionDispatch::IntegrationTest
21 def test_auto_completes
21 def test_auto_completes
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues/auto_complete" },
23 { :method => 'get', :path => "/issues/auto_complete" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingBoardsTest < ActionController::IntegrationTest
20 class RoutingBoardsTest < ActionDispatch::IntegrationTest
21 def test_boards
21 def test_boards
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/world_domination/boards" },
23 { :method => 'get', :path => "/projects/world_domination/boards" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingCalendarsTest < ActionController::IntegrationTest
20 class RoutingCalendarsTest < ActionDispatch::IntegrationTest
21 def test_calendars
21 def test_calendars
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues/calendar" },
23 { :method => 'get', :path => "/issues/calendar" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingCommentsTest < ActionController::IntegrationTest
20 class RoutingCommentsTest < ActionDispatch::IntegrationTest
21 def test_comments
21 def test_comments
22 assert_routing(
22 assert_routing(
23 { :method => 'post', :path => "/news/567/comments" },
23 { :method => 'post', :path => "/news/567/comments" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingContextMenusTest < ActionController::IntegrationTest
20 class RoutingContextMenusTest < ActionDispatch::IntegrationTest
21 def test_context_menus_time_entries
21 def test_context_menus_time_entries
22 ["get", "post"].each do |method|
22 ["get", "post"].each do |method|
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingCustomFieldsTest < ActionController::IntegrationTest
20 class RoutingCustomFieldsTest < ActionDispatch::IntegrationTest
21 def test_custom_fields
21 def test_custom_fields
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/custom_fields" },
23 { :method => 'get', :path => "/custom_fields" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingDocumentsTest < ActionController::IntegrationTest
20 class RoutingDocumentsTest < ActionDispatch::IntegrationTest
21 def test_documents_scoped_under_project
21 def test_documents_scoped_under_project
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/567/documents" },
23 { :method => 'get', :path => "/projects/567/documents" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingEnumerationsTest < ActionController::IntegrationTest
20 class RoutingEnumerationsTest < ActionDispatch::IntegrationTest
21 def test_enumerations
21 def test_enumerations
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/enumerations" },
23 { :method => 'get', :path => "/enumerations" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingFilesTest < ActionController::IntegrationTest
20 class RoutingFilesTest < ActionDispatch::IntegrationTest
21 def test_files
21 def test_files
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/33/files" },
23 { :method => 'get', :path => "/projects/33/files" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingGanttsTest < ActionController::IntegrationTest
20 class RoutingGanttsTest < ActionDispatch::IntegrationTest
21 def test_gantts
21 def test_gantts
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues/gantt" },
23 { :method => 'get', :path => "/issues/gantt" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingGroupsTest < ActionController::IntegrationTest
20 class RoutingGroupsTest < ActionDispatch::IntegrationTest
21 def test_groups_resources
21 def test_groups_resources
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/groups" },
23 { :method => 'get', :path => "/groups" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingIssueCategoriesTest < ActionController::IntegrationTest
20 class RoutingIssueCategoriesTest < ActionDispatch::IntegrationTest
21 def test_issue_categories_scoped_under_project
21 def test_issue_categories_scoped_under_project
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/foo/issue_categories" },
23 { :method => 'get', :path => "/projects/foo/issue_categories" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingIssueRelationsTest < ActionController::IntegrationTest
20 class RoutingIssueRelationsTest < ActionDispatch::IntegrationTest
21 def test_issue_relations
21 def test_issue_relations
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues/1/relations" },
23 { :method => 'get', :path => "/issues/1/relations" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingIssueStatusesTest < ActionController::IntegrationTest
20 class RoutingIssueStatusesTest < ActionDispatch::IntegrationTest
21 def test_issue_statuses
21 def test_issue_statuses
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issue_statuses" },
23 { :method => 'get', :path => "/issue_statuses" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingIssuesTest < ActionController::IntegrationTest
20 class RoutingIssuesTest < ActionDispatch::IntegrationTest
21 def test_issues_rest_actions
21 def test_issues_rest_actions
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/issues" },
23 { :method => 'get', :path => "/issues" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingJournalsTest < ActionController::IntegrationTest
20 class RoutingJournalsTest < ActionDispatch::IntegrationTest
21 def test_journals
21 def test_journals
22 assert_routing(
22 assert_routing(
23 { :method => 'post', :path => "/issues/1/quoted" },
23 { :method => 'post', :path => "/issues/1/quoted" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingMailHandlerTest < ActionController::IntegrationTest
20 class RoutingMailHandlerTest < ActionDispatch::IntegrationTest
21 def test_mail_handler
21 def test_mail_handler
22 assert_routing(
22 assert_routing(
23 { :method => "post", :path => "/mail_handler" },
23 { :method => "post", :path => "/mail_handler" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingMembersTest < ActionController::IntegrationTest
20 class RoutingMembersTest < ActionDispatch::IntegrationTest
21 def test_members
21 def test_members
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/5234/memberships.xml" },
23 { :method => 'get', :path => "/projects/5234/memberships.xml" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingMessagesTest < ActionController::IntegrationTest
20 class RoutingMessagesTest < ActionDispatch::IntegrationTest
21 def test_messages
21 def test_messages
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/boards/22/topics/2" },
23 { :method => 'get', :path => "/boards/22/topics/2" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingMyTest < ActionController::IntegrationTest
20 class RoutingMyTest < ActionDispatch::IntegrationTest
21 def test_my
21 def test_my
22 ["get", "post"].each do |method|
22 ["get", "post"].each do |method|
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingNewsTest < ActionController::IntegrationTest
20 class RoutingNewsTest < ActionDispatch::IntegrationTest
21 def test_news_index
21 def test_news_index
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/news" },
23 { :method => 'get', :path => "/news" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingPreviewsTest < ActionController::IntegrationTest
20 class RoutingPreviewsTest < ActionDispatch::IntegrationTest
21 def test_previews
21 def test_previews
22 ["get", "post", "put"].each do |method|
22 ["get", "post", "put"].each do |method|
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingProjectEnumerationsTest < ActionController::IntegrationTest
20 class RoutingProjectEnumerationsTest < ActionDispatch::IntegrationTest
21 def test_project_enumerations
21 def test_project_enumerations
22 assert_routing(
22 assert_routing(
23 { :method => 'put', :path => "/projects/64/enumerations" },
23 { :method => 'put', :path => "/projects/64/enumerations" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingProjectsTest < ActionController::IntegrationTest
20 class RoutingProjectsTest < ActionDispatch::IntegrationTest
21 def test_projects
21 def test_projects
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects" },
23 { :method => 'get', :path => "/projects" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingQueriesTest < ActionController::IntegrationTest
20 class RoutingQueriesTest < ActionDispatch::IntegrationTest
21 def test_queries
21 def test_queries
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/queries.xml" },
23 { :method => 'get', :path => "/queries.xml" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingReportsTest < ActionController::IntegrationTest
20 class RoutingReportsTest < ActionDispatch::IntegrationTest
21 def test_reports
21 def test_reports
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/567/issues/report" },
23 { :method => 'get', :path => "/projects/567/issues/report" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingRepositoriesTest < ActionController::IntegrationTest
20 class RoutingRepositoriesTest < ActionDispatch::IntegrationTest
21 def setup
21 def setup
22 @path_hash = repository_path_hash(%w[path to file.c])
22 @path_hash = repository_path_hash(%w[path to file.c])
23 assert_equal "path/to/file.c", @path_hash[:path]
23 assert_equal "path/to/file.c", @path_hash[:path]
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingRolesTest < ActionController::IntegrationTest
20 class RoutingRolesTest < ActionDispatch::IntegrationTest
21 def test_roles
21 def test_roles
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/roles" },
23 { :method => 'get', :path => "/roles" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingSearchTest < ActionController::IntegrationTest
20 class RoutingSearchTest < ActionDispatch::IntegrationTest
21 def test_search
21 def test_search
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/search" },
23 { :method => 'get', :path => "/search" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingSettingsTest < ActionController::IntegrationTest
20 class RoutingSettingsTest < ActionDispatch::IntegrationTest
21 def test_settings
21 def test_settings
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/settings" },
23 { :method => 'get', :path => "/settings" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingSysTest < ActionController::IntegrationTest
20 class RoutingSysTest < ActionDispatch::IntegrationTest
21 def test_sys
21 def test_sys
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/sys/projects" },
23 { :method => 'get', :path => "/sys/projects" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingTimelogsTest < ActionController::IntegrationTest
20 class RoutingTimelogsTest < ActionDispatch::IntegrationTest
21 def test_timelogs_global
21 def test_timelogs_global
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/time_entries" },
23 { :method => 'get', :path => "/time_entries" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingTrackersTest < ActionController::IntegrationTest
20 class RoutingTrackersTest < ActionDispatch::IntegrationTest
21 def test_trackers
21 def test_trackers
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/trackers" },
23 { :method => 'get', :path => "/trackers" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingUsersTest < ActionController::IntegrationTest
20 class RoutingUsersTest < ActionDispatch::IntegrationTest
21 def test_users
21 def test_users
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/users" },
23 { :method => 'get', :path => "/users" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingVersionsTest < ActionController::IntegrationTest
20 class RoutingVersionsTest < ActionDispatch::IntegrationTest
21 def test_roadmap
21 def test_roadmap
22 # /projects/foo/versions is /projects/foo/roadmap
22 # /projects/foo/versions is /projects/foo/roadmap
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingWatchersTest < ActionController::IntegrationTest
20 class RoutingWatchersTest < ActionDispatch::IntegrationTest
21 def test_watchers
21 def test_watchers
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/watchers/new" },
23 { :method => 'get', :path => "/watchers/new" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingWelcomeTest < ActionController::IntegrationTest
20 class RoutingWelcomeTest < ActionDispatch::IntegrationTest
21 def test_welcome
21 def test_welcome
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/" },
23 { :method => 'get', :path => "/" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingWikiTest < ActionController::IntegrationTest
20 class RoutingWikiTest < ActionDispatch::IntegrationTest
21 def test_wiki_matching
21 def test_wiki_matching
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/projects/567/wiki" },
23 { :method => 'get', :path => "/projects/567/wiki" },
@@ -54,7 +54,7 class RoutingWikiTest < ActionController::IntegrationTest
54 :id => 'CookBook_documentation', :version => '2' }
54 :id => 'CookBook_documentation', :version => '2' }
55 )
55 )
56 # Make sure we don't route wiki page sub-uris to let plugins handle them
56 # Make sure we don't route wiki page sub-uris to let plugins handle them
57 assert_raise(ActionController::RoutingError) do
57 assert_raise(Minitest::Assertion) do
58 assert_recognizes({}, {:method => 'get', :path => "/projects/1/wiki/CookBook_documentation/whatever"})
58 assert_recognizes({}, {:method => 'get', :path => "/projects/1/wiki/CookBook_documentation/whatever"})
59 end
59 end
60 end
60 end
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingWikisTest < ActionController::IntegrationTest
20 class RoutingWikisTest < ActionDispatch::IntegrationTest
21 def test_wikis_plural_admin_setup
21 def test_wikis_plural_admin_setup
22 ["get", "post"].each do |method|
22 ["get", "post"].each do |method|
23 assert_routing(
23 assert_routing(
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../../test_helper', __FILE__)
18 require File.expand_path('../../../test_helper', __FILE__)
19
19
20 class RoutingWorkflowsTest < ActionController::IntegrationTest
20 class RoutingWorkflowsTest < ActionDispatch::IntegrationTest
21 def test_workflows
21 def test_workflows
22 assert_routing(
22 assert_routing(
23 { :method => 'get', :path => "/workflows" },
23 { :method => 'get', :path => "/workflows" },
@@ -17,7 +17,7
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class UsersTest < ActionController::IntegrationTest
20 class UsersTest < ActionDispatch::IntegrationTest
21 fixtures :users
21 fixtures :users
22
22
23 def test_destroy_should_not_accept_get_requests
23 def test_destroy_should_not_accept_get_requests
@@ -14,7 +14,7 module ObjectHelpers
14
14
15 def User.add_to_project(user, project, roles=nil)
15 def User.add_to_project(user, project, roles=nil)
16 roles = Role.find(1) if roles.nil?
16 roles = Role.find(1) if roles.nil?
17 roles = [roles] unless roles.is_a?(Array)
17 roles = [roles] if roles.is_a?(Role)
18 Member.create!(:principal => user, :project => project, :roles => roles)
18 Member.create!(:principal => user, :project => project, :roles => roles)
19 end
19 end
20
20
@@ -178,14 +178,6 module ObjectHelpers
178 changeset.save!
178 changeset.save!
179 changeset
179 changeset
180 end
180 end
181
182 def Query.generate!(attributes={})
183 query = new(attributes)
184 query.name = "Generated query" if query.name.blank?
185 query.user ||= User.find(1)
186 query.save!
187 query
188 end
189 end
181 end
190
182
191 module IssueObjectHelpers
183 module IssueObjectHelpers
@@ -26,17 +26,25 include ObjectHelpers
26
26
27 require 'awesome_nested_set/version'
27 require 'awesome_nested_set/version'
28
28
29 class ActionView::TestCase
30 helper :application
31 include ApplicationHelper
32 end
33
29 class ActiveSupport::TestCase
34 class ActiveSupport::TestCase
30 include ActionDispatch::TestProcess
35 include ActionDispatch::TestProcess
36 include Shoulda::Context::Assertions
37 include Shoulda::Context::InstanceMethods
38 extend Shoulda::Context::ClassMethods
31
39
32 self.use_transactional_fixtures = true
40 self.use_transactional_fixtures = true
33 self.use_instantiated_fixtures = false
41 self.use_instantiated_fixtures = false
34
42
35 ESCAPED_CANT = 'can&#x27;t'
43 #ESCAPED_CANT = 'can&#x27;t'
36 ESCAPED_UCANT = 'Can&#x27;t'
44 #ESCAPED_UCANT = 'Can&#x27;t'
37 # Rails 4.0.2
45 # Rails 4.0.2
38 #ESCAPED_CANT = 'can&#39;t'
46 ESCAPED_CANT = 'can&#39;t'
39 #ESCAPED_UCANT = 'Can&#39;t'
47 ESCAPED_UCANT = 'Can&#39;t'
40
48
41 def log_user(login, password)
49 def log_user(login, password)
42 User.anonymous
50 User.anonymous
@@ -147,7 +155,9 class ActiveSupport::TestCase
147
155
148 # Returns the path to the test +vendor+ repository
156 # Returns the path to the test +vendor+ repository
149 def self.repository_path(vendor)
157 def self.repository_path(vendor)
150 Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
158 path = Rails.root.join("tmp/test/#{vendor.downcase}_repository").to_s
159 # Unlike ruby, JRuby returns Rails.root with backslashes under Windows
160 path.tr("\\", "/")
151 end
161 end
152
162
153 # Returns the url of the subversion test repository
163 # Returns the url of the subversion test repository
@@ -388,8 +388,7 class ChangesetTest < ActiveSupport::TestCase
388 def test_comments_should_be_converted_to_utf8
388 def test_comments_should_be_converted_to_utf8
389 proj = Project.find(3)
389 proj = Project.find(3)
390 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
390 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
391 str = "Texte encod\xe9 en ISO-8859-1."
391 str = "Texte encod\xe9 en ISO-8859-1.".force_encoding("ASCII-8BIT")
392 str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
393 r = Repository::Bazaar.create!(
392 r = Repository::Bazaar.create!(
394 :project => proj,
393 :project => proj,
395 :url => '/tmp/test/bazaar',
394 :url => '/tmp/test/bazaar',
@@ -401,18 +400,15 class ChangesetTest < ActiveSupport::TestCase
401 :scmid => '12345',
400 :scmid => '12345',
402 :comments => str)
401 :comments => str)
403 assert( c.save )
402 assert( c.save )
404 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1."
403 str_utf8 = "Texte encod\xc3\xa9 en ISO-8859-1.".force_encoding("UTF-8")
405 str_utf8.force_encoding("UTF-8") if str_utf8.respond_to?(:force_encoding)
406 assert_equal str_utf8, c.comments
404 assert_equal str_utf8, c.comments
407 end
405 end
408
406
409 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
407 def test_invalid_utf8_sequences_in_comments_should_be_replaced_latin1
410 proj = Project.find(3)
408 proj = Project.find(3)
411 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
409 # str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
412 str1 = "Texte encod\xe9 en ISO-8859-1."
410 str1 = "Texte encod\xe9 en ISO-8859-1.".force_encoding("UTF-8")
413 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
411 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
414 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
415 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
416 r = Repository::Bazaar.create!(
412 r = Repository::Bazaar.create!(
417 :project => proj,
413 :project => proj,
418 :url => '/tmp/test/bazaar',
414 :url => '/tmp/test/bazaar',
@@ -431,10 +427,7 class ChangesetTest < ActiveSupport::TestCase
431
427
432 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
428 def test_invalid_utf8_sequences_in_comments_should_be_replaced_ja_jis
433 proj = Project.find(3)
429 proj = Project.find(3)
434 str = "test\xb5\xfetest\xb5\xfe"
430 str = "test\xb5\xfetest\xb5\xfe".force_encoding('ASCII-8BIT')
435 if str.respond_to?(:force_encoding)
436 str.force_encoding('ASCII-8BIT')
437 end
438 r = Repository::Bazaar.create!(
431 r = Repository::Bazaar.create!(
439 :project => proj,
432 :project => proj,
440 :url => '/tmp/test/bazaar',
433 :url => '/tmp/test/bazaar',
@@ -453,14 +446,12 class ChangesetTest < ActiveSupport::TestCase
453 s1 = "\xC2\x80"
446 s1 = "\xC2\x80"
454 s2 = "\xc3\x82\xc2\x80"
447 s2 = "\xc3\x82\xc2\x80"
455 s4 = s2.dup
448 s4 = s2.dup
456 if s1.respond_to?(:force_encoding)
457 s3 = s1.dup
449 s3 = s1.dup
458 s1.force_encoding('ASCII-8BIT')
450 s1.force_encoding('ASCII-8BIT')
459 s2.force_encoding('ASCII-8BIT')
451 s2.force_encoding('ASCII-8BIT')
460 s3.force_encoding('ISO-8859-1')
452 s3.force_encoding('ISO-8859-1')
461 s4.force_encoding('UTF-8')
453 s4.force_encoding('UTF-8')
462 assert_equal s3.encode('UTF-8'), s4
454 assert_equal s3.encode('UTF-8'), s4
463 end
464 proj = Project.find(3)
455 proj = Project.find(3)
465 r = Repository::Bazaar.create!(
456 r = Repository::Bazaar.create!(
466 :project => proj,
457 :project => proj,
@@ -478,10 +469,8 class ChangesetTest < ActiveSupport::TestCase
478
469
479 def test_invalid_utf8_sequences_in_paths_should_be_replaced
470 def test_invalid_utf8_sequences_in_paths_should_be_replaced
480 proj = Project.find(3)
471 proj = Project.find(3)
481 str1 = "Texte encod\xe9 en ISO-8859-1"
472 str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
482 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
473 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
483 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
484 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
485 r = Repository::Bazaar.create!(
474 r = Repository::Bazaar.create!(
486 :project => proj,
475 :project => proj,
487 :url => '/tmp/test/bazaar',
476 :url => '/tmp/test/bazaar',
@@ -521,10 +510,8 class ChangesetTest < ActiveSupport::TestCase
521 assert( c.save )
510 assert( c.save )
522 assert_equal "", c.comments
511 assert_equal "", c.comments
523 assert_equal nil, c.committer
512 assert_equal nil, c.committer
524 if c.comments.respond_to?(:force_encoding)
525 assert_equal "UTF-8", c.comments.encoding.to_s
513 assert_equal "UTF-8", c.comments.encoding.to_s
526 end
514 end
527 end
528
515
529 def test_comments_empty
516 def test_comments_empty
530 proj = Project.find(3)
517 proj = Project.find(3)
@@ -542,11 +529,9 class ChangesetTest < ActiveSupport::TestCase
542 assert( c.save )
529 assert( c.save )
543 assert_equal "", c.comments
530 assert_equal "", c.comments
544 assert_equal "", c.committer
531 assert_equal "", c.committer
545 if c.comments.respond_to?(:force_encoding)
546 assert_equal "UTF-8", c.comments.encoding.to_s
532 assert_equal "UTF-8", c.comments.encoding.to_s
547 assert_equal "UTF-8", c.committer.encoding.to_s
533 assert_equal "UTF-8", c.committer.encoding.to_s
548 end
534 end
549 end
550
535
551 def test_comments_should_accept_more_than_64k
536 def test_comments_should_accept_more_than_64k
552 c = Changeset.new(:repository => Repository.first,
537 c = Changeset.new(:repository => Repository.first,
@@ -95,7 +95,6 class CustomFieldTest < ActiveSupport::TestCase
95 assert_equal ["One value", "And another one"], field.possible_values
95 assert_equal ["One value", "And another one"], field.possible_values
96 end
96 end
97
97
98 if "string".respond_to?(:encoding)
99 def test_possible_values_stored_as_binary_should_be_utf8_encoded
98 def test_possible_values_stored_as_binary_should_be_utf8_encoded
100 field = CustomField.find(11)
99 field = CustomField.find(11)
101 assert_kind_of Array, field.possible_values
100 assert_kind_of Array, field.possible_values
@@ -104,7 +103,6 class CustomFieldTest < ActiveSupport::TestCase
104 assert_equal "UTF-8", value.encoding.name
103 assert_equal "UTF-8", value.encoding.name
105 end
104 end
106 end
105 end
107 end
108
106
109 def test_destroy
107 def test_destroy
110 field = CustomField.find(1)
108 field = CustomField.find(1)
@@ -22,7 +22,7 class EnabledModuleTest < ActiveSupport::TestCase
22
22
23 def test_enabling_wiki_should_create_a_wiki
23 def test_enabling_wiki_should_create_a_wiki
24 CustomField.delete_all
24 CustomField.delete_all
25 project = Project.create!(:name => 'Project with wiki', :identifier => 'wikiproject')
25 project = Project.create!(:name => 'Project with wiki', :identifier => 'wikiproject', :enabled_module_names => [])
26 assert_nil project.wiki
26 assert_nil project.wiki
27 project.enabled_module_names = ['wiki']
27 project.enabled_module_names = ['wiki']
28 project.reload
28 project.reload
@@ -52,8 +52,7 class GroupTest < ActiveSupport::TestCase
52
52
53 def test_blank_name_error_message_fr
53 def test_blank_name_error_message_fr
54 set_language_if_valid 'fr'
54 set_language_if_valid 'fr'
55 str = "Nom doit \xc3\xaatre renseign\xc3\xa9(e)"
55 str = "Nom doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
56 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
57 g = Group.new
56 g = Group.new
58 assert !g.save
57 assert !g.save
59 assert_include str, g.errors.full_messages
58 assert_include str, g.errors.full_messages
@@ -133,20 +132,4 class GroupTest < ActiveSupport::TestCase
133
132
134 assert_equal nil, Issue.find(1).assigned_to_id
133 assert_equal nil, Issue.find(1).assigned_to_id
135 end
134 end
136
137 def test_builtin_id_with_anonymous_user_should_return_anonymous_group
138 assert_equal 13, Group.builtin_id(User.anonymous)
139 end
140
141 def test_builtin_id_with_anonymous_role_should_return_anonymous_group
142 assert_equal 13, Group.builtin_id(Role.anonymous)
143 end
144
145 def test_builtin_id_with_user_should_return_non_member_group
146 assert_equal 12, Group.builtin_id(User.find(1))
147 end
148
149 def test_builtin_id_with_non_member_role_should_return_non_member_group
150 assert_equal 12, Group.builtin_id(Role.non_member)
151 end
152 end
135 end
@@ -35,10 +35,7 class ApplicationHelperTest < ActionView::TestCase
35 def setup
35 def setup
36 super
36 super
37 set_tmp_attachments_directory
37 set_tmp_attachments_directory
38 @russian_test = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82"
38 @russian_test = "\xd1\x82\xd0\xb5\xd1\x81\xd1\x82".force_encoding('UTF-8')
39 if @russian_test.respond_to?(:force_encoding)
40 @russian_test.force_encoding('UTF-8')
41 end
42 end
39 end
43
40
44 test "#link_to_if_authorized for authorized user should allow using the :controller and :action for the target link" do
41 test "#link_to_if_authorized for authorized user should allow using the :controller and :action for the target link" do
@@ -99,7 +96,6 class ApplicationHelperTest < ActionView::TestCase
99 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
96 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
100 end
97 end
101
98
102 if 'ruby'.respond_to?(:encoding)
103 def test_auto_links_with_non_ascii_characters
99 def test_auto_links_with_non_ascii_characters
104 to_test = {
100 to_test = {
105 "http://foo.bar/#{@russian_test}" =>
101 "http://foo.bar/#{@russian_test}" =>
@@ -107,9 +103,6 class ApplicationHelperTest < ActionView::TestCase
107 }
103 }
108 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
104 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
109 end
105 end
110 else
111 puts 'Skipping test_auto_links_with_non_ascii_characters, unsupported ruby version'
112 end
113
106
114 def test_auto_mailto
107 def test_auto_mailto
115 to_test = {
108 to_test = {
@@ -254,7 +247,6 RAW
254 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
247 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
255 end
248 end
256
249
257 if 'ruby'.respond_to?(:encoding)
258 def test_textile_external_links_with_non_ascii_characters
250 def test_textile_external_links_with_non_ascii_characters
259 to_test = {
251 to_test = {
260 %|This is a "link":http://foo.bar/#{@russian_test}| =>
252 %|This is a "link":http://foo.bar/#{@russian_test}| =>
@@ -262,9 +254,6 RAW
262 }
254 }
263 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
255 to_test.each { |text, result| assert_equal "<p>#{result}</p>", textilizable(text) }
264 end
256 end
265 else
266 puts 'Skipping test_textile_external_links_with_non_ascii_characters, unsupported ruby version'
267 end
268
257
269 def test_redmine_links
258 def test_redmine_links
270 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
259 issue_link = link_to('#3', {:controller => 'issues', :action => 'show', :id => 3},
@@ -1336,13 +1325,8 RAW
1336 project = Project.find(1)
1325 project = Project.find(1)
1337 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
1326 assert_equal %(<a href="/projects/ecookbook">eCookbook</a>),
1338 link_to_project(project)
1327 link_to_project(project)
1339 assert_equal %(<a href="/projects/ecookbook/settings">eCookbook</a>),
1340 link_to_project(project, :action => 'settings')
1341 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
1328 assert_equal %(<a href="http://test.host/projects/ecookbook?jump=blah">eCookbook</a>),
1342 link_to_project(project, {:only_path => false, :jump => 'blah'})
1329 link_to_project(project, {:only_path => false, :jump => 'blah'})
1343 result = link_to("eCookbook", "/projects/ecookbook/settings", :class => "project")
1344 assert_equal result,
1345 link_to_project(project, {:action => 'settings'}, :class => "project")
1346 end
1330 end
1347
1331
1348 def test_link_to_project_settings
1332 def test_link_to_project_settings
@@ -1433,7 +1417,7 RAW
1433
1417
1434 def test_raw_json_should_escape_closing_tags
1418 def test_raw_json_should_escape_closing_tags
1435 s = raw_json(["<foo>bar</foo>"])
1419 s = raw_json(["<foo>bar</foo>"])
1436 assert_equal '["<foo>bar<\/foo>"]', s
1420 assert_include '\/foo', s
1437 end
1421 end
1438
1422
1439 def test_raw_json_should_be_html_safe
1423 def test_raw_json_should_be_html_safe
@@ -1508,8 +1492,7 RAW
1508 end
1492 end
1509
1493
1510 def test_truncate_single_line_non_ascii
1494 def test_truncate_single_line_non_ascii
1511 ja = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"
1495 ja = "\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e".force_encoding('UTF-8')
1512 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
1513 result = truncate_single_line_raw("#{ja}\n#{ja}\n#{ja}", 10)
1496 result = truncate_single_line_raw("#{ja}\n#{ja}\n#{ja}", 10)
1514 assert_equal "#{ja} #{ja}...", result
1497 assert_equal "#{ja} #{ja}...", result
1515 assert !result.html_safe?
1498 assert !result.html_safe?
@@ -42,23 +42,16 class ProjectsHelperTest < ActionView::TestCase
42 def test_link_to_version_within_project
42 def test_link_to_version_within_project
43 @project = Project.find(2)
43 @project = Project.find(2)
44 User.current = User.find(1)
44 User.current = User.find(1)
45 assert_equal '<a href="/versions/5" title="07/01/2006">Alpha</a>', link_to_version(Version.find(5))
45 assert_equal '<a href="/versions/5">Alpha</a>', link_to_version(Version.find(5))
46 end
46 end
47
47
48 def test_link_to_version
48 def test_link_to_version
49 User.current = User.find(1)
49 User.current = User.find(1)
50 assert_equal '<a href="/versions/5" title="07/01/2006">Alpha</a>', link_to_version(Version.find(5))
50 assert_equal '<a href="/versions/5">OnlineStore - Alpha</a>', link_to_version(Version.find(5))
51 end
52
53 def test_link_to_version_without_effective_date
54 User.current = User.find(1)
55 version = Version.find(5)
56 version.effective_date = nil
57 assert_equal '<a href="/versions/5">Alpha</a>', link_to_version(version)
58 end
51 end
59
52
60 def test_link_to_private_version
53 def test_link_to_private_version
61 assert_equal 'Alpha', link_to_version(Version.find(5))
54 assert_equal 'OnlineStore - Alpha', link_to_version(Version.find(5))
62 end
55 end
63
56
64 def test_link_to_version_invalid_version
57 def test_link_to_version_invalid_version
@@ -71,20 +64,11 class ProjectsHelperTest < ActionView::TestCase
71 end
64 end
72
65
73 def test_format_version_name
66 def test_format_version_name
74 assert_equal "0.1", format_version_name(Version.find(1))
67 assert_equal "eCookbook - 0.1", format_version_name(Version.find(1))
75 end
76
77 def test_format_version_name_for_shared_version_within_project_should_not_display_project_name
78 @project = Project.find(1)
79 version = Version.find(1)
80 version.sharing = 'system'
81 assert_equal "0.1", format_version_name(version)
82 end
68 end
83
69
84 def test_format_version_name_for_shared_version_should_display_project_name
70 def test_format_version_name_for_system_version
85 version = Version.find(1)
71 assert_equal "OnlineStore - Systemwide visible version", format_version_name(Version.find(7))
86 version.sharing = 'system'
87 assert_equal "eCookbook - 0.1", format_version_name(version)
88 end
72 end
89
73
90 def test_version_options_for_select_with_no_versions
74 def test_version_options_for_select_with_no_versions
@@ -47,7 +47,6 class PatchesTest < ActiveSupport::TestCase
47 end
47 end
48
48
49 # https://github.com/rails/rails/pull/14198/files
49 # https://github.com/rails/rails/pull/14198/files
50 if RUBY_VERSION >= "1.9"
51 def test_indifferent_select
50 def test_indifferent_select
52 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).select { |_ ,v| v == 1 }
51 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).select { |_ ,v| v == 1 }
53 assert_equal({ 'a' => 1 }, hash)
52 assert_equal({ 'a' => 1 }, hash)
@@ -62,7 +61,6 class PatchesTest < ActiveSupport::TestCase
62 assert_equal({ 'a' => 1 }, indifferent_strings)
61 assert_equal({ 'a' => 1 }, indifferent_strings)
63 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
62 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
64 end
63 end
65 end
66
64
67 def test_indifferent_reject
65 def test_indifferent_reject
68 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).reject { |_, v| v != 1 }
66 hash = ActiveSupport::HashWithIndifferentAccess.new(@symbols).reject { |_, v| v != 1 }
@@ -77,7 +75,6 class PatchesTest < ActiveSupport::TestCase
77 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
75 assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings
78 end
76 end
79
77
80 if RUBY_VERSION >= "1.9"
81 def test_select
78 def test_select
82 assert_equal @keys, @ordered_hash.select { true }.map(&:first)
79 assert_equal @keys, @ordered_hash.select { true }.map(&:first)
83 new_ordered_hash = @ordered_hash.select { true }
80 new_ordered_hash = @ordered_hash.select { true }
@@ -86,7 +83,6 class PatchesTest < ActiveSupport::TestCase
86 Hash : ActiveSupport::OrderedHash),
83 Hash : ActiveSupport::OrderedHash),
87 new_ordered_hash
84 new_ordered_hash
88 end
85 end
89 end
90
86
91 def test_reject
87 def test_reject
92 copy = @ordered_hash.dup
88 copy = @ordered_hash.dup
@@ -416,7 +416,7 class IssueNestedSetTest < ActiveSupport::TestCase
416 c.reload
416 c.reload
417
417
418 assert_equal 5, c.issues.count
418 assert_equal 5, c.issues.count
419 ic1, ic2, ic3, ic4, ic5 = c.issues.order('subject').all
419 ic1, ic2, ic3, ic4, ic5 = c.issues.order('subject').to_a
420 assert ic1.root?
420 assert ic1.root?
421 assert_equal ic1, ic2.parent
421 assert_equal ic1, ic2.parent
422 assert_equal ic1, ic3.parent
422 assert_equal ic1, ic3.parent
@@ -83,7 +83,7 class IssuePriorityTest < ActiveSupport::TestCase
83 IssuePriority.clear_position_names
83 IssuePriority.clear_position_names
84
84
85 IssuePriority.compute_position_names
85 IssuePriority.compute_position_names
86 assert_equal %w(lowest default high3 high2 highest), IssuePriority.active.all.sort.map(&:position_name)
86 assert_equal %w(lowest default high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
87 end
87 end
88
88
89 def test_compute_position_names_without_default_priority_should_split_priorities
89 def test_compute_position_names_without_default_priority_should_split_priorities
@@ -91,16 +91,16 class IssuePriorityTest < ActiveSupport::TestCase
91 IssuePriority.update_all :is_default => false
91 IssuePriority.update_all :is_default => false
92
92
93 IssuePriority.compute_position_names
93 IssuePriority.compute_position_names
94 assert_equal %w(lowest low2 default high2 highest), IssuePriority.active.all.sort.map(&:position_name)
94 assert_equal %w(lowest low2 default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
95 end
95 end
96
96
97 def test_adding_a_priority_should_update_position_names
97 def test_adding_a_priority_should_update_position_names
98 priority = IssuePriority.create!(:name => 'New')
98 priority = IssuePriority.create!(:name => 'New')
99 assert_equal %w(lowest default high4 high3 high2 highest), IssuePriority.active.all.sort.map(&:position_name)
99 assert_equal %w(lowest default high4 high3 high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
100 end
100 end
101
101
102 def test_destroying_a_priority_should_update_position_names
102 def test_destroying_a_priority_should_update_position_names
103 IssuePriority.find_by_position_name('highest').destroy
103 IssuePriority.find_by_position_name('highest').destroy
104 assert_equal %w(lowest default high2 highest), IssuePriority.active.all.sort.map(&:position_name)
104 assert_equal %w(lowest default high2 highest), IssuePriority.active.to_a.sort.map(&:position_name)
105 end
105 end
106 end
106 end
@@ -112,7 +112,7 class IssueStatusTest < ActiveSupport::TestCase
112 end
112 end
113
113
114 def test_sorted_scope
114 def test_sorted_scope
115 assert_equal IssueStatus.all.sort, IssueStatus.sorted.all
115 assert_equal IssueStatus.all.sort, IssueStatus.sorted.to_a
116 end
116 end
117
117
118 def test_named_scope
118 def test_named_scope
@@ -204,7 +204,7 class IssueTest < ActiveSupport::TestCase
204
204
205 def test_visible_scope_for_anonymous
205 def test_visible_scope_for_anonymous
206 # Anonymous user should see issues of public projects only
206 # Anonymous user should see issues of public projects only
207 issues = Issue.visible(User.anonymous).all
207 issues = Issue.visible(User.anonymous).to_a
208 assert issues.any?
208 assert issues.any?
209 assert_nil issues.detect {|issue| !issue.project.is_public?}
209 assert_nil issues.detect {|issue| !issue.project.is_public?}
210 assert_nil issues.detect {|issue| issue.is_private?}
210 assert_nil issues.detect {|issue| issue.is_private?}
@@ -214,7 +214,7 class IssueTest < ActiveSupport::TestCase
214 def test_visible_scope_for_anonymous_without_view_issues_permissions
214 def test_visible_scope_for_anonymous_without_view_issues_permissions
215 # Anonymous user should not see issues without permission
215 # Anonymous user should not see issues without permission
216 Role.anonymous.remove_permission!(:view_issues)
216 Role.anonymous.remove_permission!(:view_issues)
217 issues = Issue.visible(User.anonymous).all
217 issues = Issue.visible(User.anonymous).to_a
218 assert issues.empty?
218 assert issues.empty?
219 assert_visibility_match User.anonymous, issues
219 assert_visibility_match User.anonymous, issues
220 end
220 end
@@ -247,7 +247,7 class IssueTest < ActiveSupport::TestCase
247 user = User.find(9)
247 user = User.find(9)
248 assert user.projects.empty?
248 assert user.projects.empty?
249 # Non member user should see issues of public projects only
249 # Non member user should see issues of public projects only
250 issues = Issue.visible(user).all
250 issues = Issue.visible(user).to_a
251 assert issues.any?
251 assert issues.any?
252 assert_nil issues.detect {|issue| !issue.project.is_public?}
252 assert_nil issues.detect {|issue| !issue.project.is_public?}
253 assert_nil issues.detect {|issue| issue.is_private?}
253 assert_nil issues.detect {|issue| issue.is_private?}
@@ -259,7 +259,7 class IssueTest < ActiveSupport::TestCase
259 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
259 Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 9, :subject => 'Issue by non member')
260 user = User.find(9)
260 user = User.find(9)
261
261
262 issues = Issue.visible(user).all
262 issues = Issue.visible(user).to_a
263 assert issues.any?
263 assert issues.any?
264 assert_nil issues.detect {|issue| issue.author != user}
264 assert_nil issues.detect {|issue| issue.author != user}
265 assert_visibility_match user, issues
265 assert_visibility_match user, issues
@@ -270,7 +270,7 class IssueTest < ActiveSupport::TestCase
270 Role.non_member.remove_permission!(:view_issues)
270 Role.non_member.remove_permission!(:view_issues)
271 user = User.find(9)
271 user = User.find(9)
272 assert user.projects.empty?
272 assert user.projects.empty?
273 issues = Issue.visible(user).all
273 issues = Issue.visible(user).to_a
274 assert issues.empty?
274 assert issues.empty?
275 assert_visibility_match user, issues
275 assert_visibility_match user, issues
276 end
276 end
@@ -291,7 +291,7 class IssueTest < ActiveSupport::TestCase
291 # User should see issues of projects for which user has view_issues permissions only
291 # User should see issues of projects for which user has view_issues permissions only
292 Role.non_member.remove_permission!(:view_issues)
292 Role.non_member.remove_permission!(:view_issues)
293 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
293 Member.create!(:principal => user, :project_id => 3, :role_ids => [2])
294 issues = Issue.visible(user).all
294 issues = Issue.visible(user).to_a
295 assert issues.any?
295 assert issues.any?
296 assert_nil issues.detect {|issue| issue.project_id != 3}
296 assert_nil issues.detect {|issue| issue.project_id != 3}
297 assert_nil issues.detect {|issue| issue.is_private?}
297 assert_nil issues.detect {|issue| issue.is_private?}
@@ -311,12 +311,12 class IssueTest < ActiveSupport::TestCase
311 :is_private => true)
311 :is_private => true)
312
312
313 Role.find(2).update_attribute :issues_visibility, 'default'
313 Role.find(2).update_attribute :issues_visibility, 'default'
314 issues = Issue.visible(User.find(8)).all
314 issues = Issue.visible(User.find(8)).to_a
315 assert issues.any?
315 assert issues.any?
316 assert issues.include?(issue)
316 assert issues.include?(issue)
317
317
318 Role.find(2).update_attribute :issues_visibility, 'own'
318 Role.find(2).update_attribute :issues_visibility, 'own'
319 issues = Issue.visible(User.find(8)).all
319 issues = Issue.visible(User.find(8)).to_a
320 assert issues.any?
320 assert issues.any?
321 assert issues.include?(issue)
321 assert issues.include?(issue)
322 end
322 end
@@ -325,7 +325,7 class IssueTest < ActiveSupport::TestCase
325 user = User.find(1)
325 user = User.find(1)
326 user.members.each(&:destroy)
326 user.members.each(&:destroy)
327 assert user.projects.empty?
327 assert user.projects.empty?
328 issues = Issue.visible(user).all
328 issues = Issue.visible(user).to_a
329 assert issues.any?
329 assert issues.any?
330 # Admin should see issues on private projects that admin does not belong to
330 # Admin should see issues on private projects that admin does not belong to
331 assert issues.detect {|issue| !issue.project.is_public?}
331 assert issues.detect {|issue| !issue.project.is_public?}
@@ -336,7 +336,7 class IssueTest < ActiveSupport::TestCase
336
336
337 def test_visible_scope_with_project
337 def test_visible_scope_with_project
338 project = Project.find(1)
338 project = Project.find(1)
339 issues = Issue.visible(User.find(2), :project => project).all
339 issues = Issue.visible(User.find(2), :project => project).to_a
340 projects = issues.collect(&:project).uniq
340 projects = issues.collect(&:project).uniq
341 assert_equal 1, projects.size
341 assert_equal 1, projects.size
342 assert_equal project, projects.first
342 assert_equal project, projects.first
@@ -344,7 +344,7 class IssueTest < ActiveSupport::TestCase
344
344
345 def test_visible_scope_with_project_and_subprojects
345 def test_visible_scope_with_project_and_subprojects
346 project = Project.find(1)
346 project = Project.find(1)
347 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).all
347 issues = Issue.visible(User.find(2), :project => project, :with_subprojects => true).to_a
348 projects = issues.collect(&:project).uniq
348 projects = issues.collect(&:project).uniq
349 assert projects.size > 1
349 assert projects.size > 1
350 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
350 assert_equal [], projects.select {|p| !p.is_or_is_descendant_of?(project)}
@@ -370,13 +370,20 class IssueTest < ActiveSupport::TestCase
370 assert_equal 2, parent.descendants.visible(user).collect{|i| i}.size
370 assert_equal 2, parent.descendants.visible(user).collect{|i| i}.size
371 end
371 end
372
372
373 def test_visible_scope_with_unsaved_user_should_not_raise_an_error
374 user = User.new
375 assert_nothing_raised do
376 Issue.visible(user).to_a
377 end
378 end
379
373 def test_open_scope
380 def test_open_scope
374 issues = Issue.open.all
381 issues = Issue.open.to_a
375 assert_nil issues.detect(&:closed?)
382 assert_nil issues.detect(&:closed?)
376 end
383 end
377
384
378 def test_open_scope_with_arg
385 def test_open_scope_with_arg
379 issues = Issue.open(false).all
386 issues = Issue.open(false).to_a
380 assert_equal issues, issues.select(&:closed?)
387 assert_equal issues, issues.select(&:closed?)
381 end
388 end
382
389
@@ -1289,7 +1296,7 class IssueTest < ActiveSupport::TestCase
1289 end
1296 end
1290
1297
1291 test "#copy should not create a journal" do
1298 test "#copy should not create a journal" do
1292 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :assigned_to_id => 3)
1299 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :assigned_to_id => 3}, :link => false)
1293 copy.save!
1300 copy.save!
1294 assert_equal 0, copy.reload.journals.size
1301 assert_equal 0, copy.reload.journals.size
1295 end
1302 end
@@ -1325,7 +1332,7 class IssueTest < ActiveSupport::TestCase
1325 test "#copy should create a journal with notes" do
1332 test "#copy should create a journal with notes" do
1326 date = Date.today
1333 date = Date.today
1327 notes = "Notes added when copying"
1334 notes = "Notes added when copying"
1328 copy = Issue.find(1).copy(:project_id => 3, :tracker_id => 2, :start_date => date)
1335 copy = Issue.find(1).copy({:project_id => 3, :tracker_id => 2, :start_date => date}, :link => false)
1329 copy.init_journal(User.current, notes)
1336 copy.init_journal(User.current, notes)
1330 copy.save!
1337 copy.save!
1331
1338
@@ -1619,6 +1626,7 class IssueTest < ActiveSupport::TestCase
1619 issue2.reload
1626 issue2.reload
1620 assert_equal Date.parse('2012-10-18'), issue2.start_date
1627 assert_equal Date.parse('2012-10-18'), issue2.start_date
1621
1628
1629 with_settings :date_format => '%m/%d/%Y' do
1622 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1630 child = Issue.new(:parent_issue_id => issue2.id, :start_date => '2012-10-16',
1623 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1631 :project_id => 1, :tracker_id => 1, :status_id => 1, :subject => 'Child', :author_id => 1)
1624 assert !child.valid?
1632 assert !child.valid?
@@ -1627,6 +1635,7 class IssueTest < ActiveSupport::TestCase
1627 child.start_date = '2012-10-18'
1635 child.start_date = '2012-10-18'
1628 assert child.save
1636 assert child.save
1629 end
1637 end
1638 end
1630
1639
1631 def test_setting_parent_to_a_dependent_issue_should_not_validate
1640 def test_setting_parent_to_a_dependent_issue_should_not_validate
1632 set_language_if_valid 'en'
1641 set_language_if_valid 'en'
@@ -27,6 +27,7 class JournalTest < ActiveSupport::TestCase
27
27
28 def setup
28 def setup
29 @journal = Journal.find 1
29 @journal = Journal.find 1
30 User.current = nil
30 end
31 end
31
32
32 def test_journalized_is_an_issue
33 def test_journalized_is_an_issue
@@ -119,12 +120,12 class JournalTest < ActiveSupport::TestCase
119
120
120 def test_visible_scope_for_anonymous
121 def test_visible_scope_for_anonymous
121 # Anonymous user should see issues of public projects only
122 # Anonymous user should see issues of public projects only
122 journals = Journal.visible(User.anonymous).all
123 journals = Journal.visible(User.anonymous).to_a
123 assert journals.any?
124 assert journals.any?
124 assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
125 assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
125 # Anonymous user should not see issues without permission
126 # Anonymous user should not see issues without permission
126 Role.anonymous.remove_permission!(:view_issues)
127 Role.anonymous.remove_permission!(:view_issues)
127 journals = Journal.visible(User.anonymous).all
128 journals = Journal.visible(User.anonymous).to_a
128 assert journals.empty?
129 assert journals.empty?
129 end
130 end
130
131
@@ -132,18 +133,18 class JournalTest < ActiveSupport::TestCase
132 user = User.find(9)
133 user = User.find(9)
133 assert user.projects.empty?
134 assert user.projects.empty?
134 # Non member user should see issues of public projects only
135 # Non member user should see issues of public projects only
135 journals = Journal.visible(user).all
136 journals = Journal.visible(user).to_a
136 assert journals.any?
137 assert journals.any?
137 assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
138 assert_nil journals.detect {|journal| !journal.issue.project.is_public?}
138 # Non member user should not see issues without permission
139 # Non member user should not see issues without permission
139 Role.non_member.remove_permission!(:view_issues)
140 Role.non_member.remove_permission!(:view_issues)
140 user.reload
141 user.reload
141 journals = Journal.visible(user).all
142 journals = Journal.visible(user).to_a
142 assert journals.empty?
143 assert journals.empty?
143 # User should see issues of projects for which user has view_issues permissions only
144 # User should see issues of projects for which user has view_issues permissions only
144 Member.create!(:principal => user, :project_id => 1, :role_ids => [1])
145 Member.create!(:principal => user, :project_id => 1, :role_ids => [1])
145 user.reload
146 user.reload
146 journals = Journal.visible(user).all
147 journals = Journal.visible(user).to_a
147 assert journals.any?
148 assert journals.any?
148 assert_nil journals.detect {|journal| journal.issue.project_id != 1}
149 assert_nil journals.detect {|journal| journal.issue.project_id != 1}
149 end
150 end
@@ -152,7 +153,7 class JournalTest < ActiveSupport::TestCase
152 user = User.find(1)
153 user = User.find(1)
153 user.members.each(&:destroy)
154 user.members.each(&:destroy)
154 assert user.projects.empty?
155 assert user.projects.empty?
155 journals = Journal.visible(user).all
156 journals = Journal.visible(user).to_a
156 assert journals.any?
157 assert journals.any?
157 # Admin should see issues on private projects that admin does not belong to
158 # Admin should see issues on private projects that admin does not belong to
158 assert journals.detect {|journal| !journal.issue.project.is_public?}
159 assert journals.detect {|journal| !journal.issue.project.is_public?}
@@ -21,14 +21,9 class Redmine::CodesetUtilTest < ActiveSupport::TestCase
21
21
22 def test_to_utf8_by_setting_from_latin1
22 def test_to_utf8_by_setting_from_latin1
23 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
23 with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do
24 s1 = "Texte encod\xc3\xa9"
24 s1 = "Texte encod\xc3\xa9".force_encoding("UTF-8")
25 s2 = "Texte encod\xe9"
25 s2 = "Texte encod\xe9".force_encoding("ASCII-8BIT")
26 s3 = s2.dup
26 s3 = s2.dup.force_encoding("UTF-8")
27 if s1.respond_to?(:force_encoding)
28 s1.force_encoding("UTF-8")
29 s2.force_encoding("ASCII-8BIT")
30 s3.force_encoding("UTF-8")
31 end
32 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
27 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
33 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
28 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
34 end
29 end
@@ -36,14 +31,9 class Redmine::CodesetUtilTest < ActiveSupport::TestCase
36
31
37 def test_to_utf8_by_setting_from_euc_jp
32 def test_to_utf8_by_setting_from_euc_jp
38 with_settings :repositories_encodings => 'UTF-8,EUC-JP' do
33 with_settings :repositories_encodings => 'UTF-8,EUC-JP' do
39 s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3"
34 s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3".force_encoding("UTF-8")
40 s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3"
35 s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3".force_encoding("ASCII-8BIT")
41 s3 = s2.dup
36 s3 = s2.dup.force_encoding("UTF-8")
42 if s1.respond_to?(:force_encoding)
43 s1.force_encoding("UTF-8")
44 s2.force_encoding("ASCII-8BIT")
45 s3.force_encoding("UTF-8")
46 end
47 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
37 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
48 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
38 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
49 end
39 end
@@ -51,14 +41,9 class Redmine::CodesetUtilTest < ActiveSupport::TestCase
51
41
52 def test_to_utf8_by_setting_should_be_converted_all_latin1
42 def test_to_utf8_by_setting_should_be_converted_all_latin1
53 with_settings :repositories_encodings => 'ISO-8859-1' do
43 with_settings :repositories_encodings => 'ISO-8859-1' do
54 s1 = "\xc3\x82\xc2\x80"
44 s1 = "\xc3\x82\xc2\x80".force_encoding("UTF-8")
55 s2 = "\xC2\x80"
45 s2 = "\xC2\x80".force_encoding("ASCII-8BIT")
56 s3 = s2.dup
46 s3 = s2.dup.force_encoding("UTF-8")
57 if s1.respond_to?(:force_encoding)
58 s1.force_encoding("UTF-8")
59 s2.force_encoding("ASCII-8BIT")
60 s3.force_encoding("UTF-8")
61 end
62 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
47 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s2)
63 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
48 assert_equal s1, Redmine::CodesetUtil.to_utf8_by_setting(s3)
64 end
49 end
@@ -70,45 +55,33 class Redmine::CodesetUtilTest < ActiveSupport::TestCase
70 end
55 end
71
56
72 def test_to_utf8_by_setting_returns_ascii_as_utf8
57 def test_to_utf8_by_setting_returns_ascii_as_utf8
73 s1 = "ASCII"
58 s1 = "ASCII".force_encoding("UTF-8")
74 s2 = s1.dup
59 s2 = s1.dup.force_encoding("ISO-8859-1")
75 if s1.respond_to?(:force_encoding)
76 s1.force_encoding("UTF-8")
77 s2.force_encoding("ISO-8859-1")
78 end
79 str1 = Redmine::CodesetUtil.to_utf8_by_setting(s1)
60 str1 = Redmine::CodesetUtil.to_utf8_by_setting(s1)
80 str2 = Redmine::CodesetUtil.to_utf8_by_setting(s2)
61 str2 = Redmine::CodesetUtil.to_utf8_by_setting(s2)
81 assert_equal s1, str1
62 assert_equal s1, str1
82 assert_equal s1, str2
63 assert_equal s1, str2
83 if s1.respond_to?(:force_encoding)
84 assert_equal "UTF-8", str1.encoding.to_s
64 assert_equal "UTF-8", str1.encoding.to_s
85 assert_equal "UTF-8", str2.encoding.to_s
65 assert_equal "UTF-8", str2.encoding.to_s
86 end
66 end
87 end
88
67
89 def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped
68 def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped
90 with_settings :repositories_encodings => '' do
69 with_settings :repositories_encodings => '' do
91 # s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
70 # s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt")
92 s1 = "Texte encod\xe9 en ISO-8859-1."
71 s1 = "Texte encod\xe9 en ISO-8859-1.".force_encoding("ASCII-8BIT")
93 s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding)
94 str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
72 str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
95 if str.respond_to?(:force_encoding)
96 assert str.valid_encoding?
73 assert str.valid_encoding?
97 assert_equal "UTF-8", str.encoding.to_s
74 assert_equal "UTF-8", str.encoding.to_s
98 end
99 assert_equal "Texte encod? en ISO-8859-1.", str
75 assert_equal "Texte encod? en ISO-8859-1.", str
100 end
76 end
101 end
77 end
102
78
103 def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped_ja_jis
79 def test_to_utf8_by_setting_invalid_utf8_sequences_should_be_stripped_ja_jis
104 with_settings :repositories_encodings => 'ISO-2022-JP' do
80 with_settings :repositories_encodings => 'ISO-2022-JP' do
105 s1 = "test\xb5\xfetest\xb5\xfe"
81 s1 = "test\xb5\xfetest\xb5\xfe".force_encoding("ASCII-8BIT")
106 s1.force_encoding("ASCII-8BIT") if s1.respond_to?(:force_encoding)
107 str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
82 str = Redmine::CodesetUtil.to_utf8_by_setting(s1)
108 if str.respond_to?(:force_encoding)
109 assert str.valid_encoding?
83 assert str.valid_encoding?
110 assert_equal "UTF-8", str.encoding.to_s
84 assert_equal "UTF-8", str.encoding.to_s
111 end
112 assert_equal "test??test??", str
85 assert_equal "test??test??", str
113 end
86 end
114 end
87 end
@@ -27,11 +27,10 class PdfTest < ActiveSupport::TestCase
27 end
27 end
28
28
29 def test_rdm_pdf_iconv_cannot_convert_ja_cp932
29 def test_rdm_pdf_iconv_cannot_convert_ja_cp932
30 encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" )
31 utf8_txt_1 = "\xe7\x8b\x80\xe6\x85\x8b"
30 utf8_txt_1 = "\xe7\x8b\x80\xe6\x85\x8b"
32 utf8_txt_2 = "\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
31 utf8_txt_2 = "\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
33 utf8_txt_3 = "\xe7\x8b\x80\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
32 utf8_txt_3 = "\xe7\x8b\x80\xe7\x8b\x80\xe6\x85\x8b\xe7\x8b\x80"
34 if utf8_txt_1.respond_to?(:force_encoding)
33 ["CP932", "SJIS"].each do |encoding|
35 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding)
34 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding)
36 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding)
35 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding)
37 txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding)
36 txt_3 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding)
@@ -41,64 +40,40 class PdfTest < ActiveSupport::TestCase
41 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
40 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
42 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
41 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
43 assert_equal "ASCII-8BIT", txt_3.encoding.to_s
42 assert_equal "ASCII-8BIT", txt_3.encoding.to_s
44 elsif RUBY_PLATFORM == 'java'
45 assert_equal "??",
46 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding)
47 assert_equal "???",
48 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding)
49 assert_equal "????",
50 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding)
51 else
52 assert_equal "???\x91\xd4",
53 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_1, encoding)
54 assert_equal "???\x91\xd4???",
55 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_2, encoding)
56 assert_equal "??????\x91\xd4???",
57 Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(utf8_txt_3, encoding)
58 end
43 end
59 end
44 end
60
45
61 def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_en
46 def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_en
62 str1 = "Texte encod\xe9 en ISO-8859-1"
47 str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
63 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
48 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
64 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
65 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
66 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, 'UTF-8')
49 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, 'UTF-8')
67 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, 'UTF-8')
50 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, 'UTF-8')
68 if txt_1.respond_to?(:force_encoding)
69 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
51 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
70 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
52 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
71 end
72 assert_equal "Texte encod? en ISO-8859-1", txt_1
53 assert_equal "Texte encod? en ISO-8859-1", txt_1
73 assert_equal "?a?b?c?d?e test", txt_2
54 assert_equal "?a?b?c?d?e test", txt_2
74 end
55 end
75
56
76 def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_ja
57 def test_rdm_pdf_iconv_invalid_utf8_should_be_replaced_ja
77 str1 = "Texte encod\xe9 en ISO-8859-1"
58 str1 = "Texte encod\xe9 en ISO-8859-1".force_encoding("UTF-8")
78 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test"
59 str2 = "\xe9a\xe9b\xe9c\xe9d\xe9e test".force_encoding("ASCII-8BIT")
79 str1.force_encoding("UTF-8") if str1.respond_to?(:force_encoding)
80 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
81 encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" )
60 encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" )
82 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, encoding)
61 txt_1 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str1, encoding)
83 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, encoding)
62 txt_2 = Redmine::Export::PDF::RDMPdfEncoding::rdm_from_utf8(str2, encoding)
84 if txt_1.respond_to?(:force_encoding)
85 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
63 assert_equal "ASCII-8BIT", txt_1.encoding.to_s
86 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
64 assert_equal "ASCII-8BIT", txt_2.encoding.to_s
87 end
88 assert_equal "Texte encod? en ISO-8859-1", txt_1
65 assert_equal "Texte encod? en ISO-8859-1", txt_1
89 assert_equal "?a?b?c?d?e test", txt_2
66 assert_equal "?a?b?c?d?e test", txt_2
90 end
67 end
91
68
92 def test_attach
69 def test_attach
70 ["CP932", "SJIS"].each do |encoding|
93 set_fixtures_attachments_directory
71 set_fixtures_attachments_directory
94
72
95 str2 = "\x83e\x83X\x83g"
73 str2 = "\x83e\x83X\x83g".force_encoding("ASCII-8BIT")
96 str2.force_encoding("ASCII-8BIT") if str2.respond_to?(:force_encoding)
97 encoding = ( RUBY_PLATFORM == 'java' ? "SJIS" : "CP932" )
98
74
99 a1 = Attachment.find(17)
75 a1 = Attachment.find(17)
100 a2 = Attachment.find(19)
76 a2 = Attachment.find(19)
101
102 User.current = User.find(1)
77 User.current = User.find(1)
103 assert a1.readable?
78 assert a1.readable?
104 assert a1.visible?
79 assert a1.visible?
@@ -108,6 +83,7 class PdfTest < ActiveSupport::TestCase
108 aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
83 aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
109 assert_not_nil aa1
84 assert_not_nil aa1
110 assert_equal 17, aa1.id
85 assert_equal 17, aa1.id
86
111 aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
87 aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
112 assert_not_nil aa2
88 assert_not_nil aa2
113 assert_equal 19, aa2.id
89 assert_equal 19, aa2.id
@@ -117,7 +93,6 class PdfTest < ActiveSupport::TestCase
117 assert (! a1.visible?)
93 assert (! a1.visible?)
118 assert a2.readable?
94 assert a2.readable?
119 assert (! a2.visible?)
95 assert (! a2.visible?)
120
121 aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
96 aa1 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "Testfile.PNG", "UTF-8")
122 assert_equal nil, aa1
97 assert_equal nil, aa1
123 aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
98 aa2 = Redmine::Export::PDF::RDMPdfEncoding::attach(Attachment.all, "test#{str2}.png", encoding)
@@ -126,3 +101,4 class PdfTest < ActiveSupport::TestCase
126 set_tmp_attachments_directory
101 set_tmp_attachments_directory
127 end
102 end
128 end
103 end
104 end
@@ -66,6 +66,7 class Redmine::Hook::ManagerTest < ActionView::TestCase
66
66
67 def setup
67 def setup
68 @hook_module = Redmine::Hook
68 @hook_module = Redmine::Hook
69 @hook_module.clear_listeners
69 end
70 end
70
71
71 def teardown
72 def teardown
@@ -32,31 +32,33 class Redmine::I18nTest < ActiveSupport::TestCase
32 def test_date_format_default
32 def test_date_format_default
33 set_language_if_valid 'en'
33 set_language_if_valid 'en'
34 today = Date.today
34 today = Date.today
35 Setting.date_format = ''
35 with_settings :date_format => '' do
36 assert_equal I18n.l(today), format_date(today)
36 assert_equal I18n.l(today), format_date(today)
37 end
37 end
38 end
38
39
39 def test_date_format
40 def test_date_format
40 set_language_if_valid 'en'
41 set_language_if_valid 'en'
41 today = Date.today
42 today = Date.today
42 Setting.date_format = '%d %m %Y'
43 with_settings :date_format => '%d %m %Y' do
43 assert_equal today.strftime('%d %m %Y'), format_date(today)
44 assert_equal today.strftime('%d %m %Y'), format_date(today)
44 end
45 end
46 end
45
47
46 def test_date_format_default_with_user_locale
48 def test_date_format_default_with_user_locale
47 set_language_if_valid 'es'
49 set_language_if_valid 'es'
48 today = now = Time.parse('2011-02-20 14:00:00')
50 today = now = Time.parse('2011-02-20 14:00:00')
49 Setting.date_format = '%d %B %Y'
51 with_settings :date_format => '%d %B %Y' do
50 User.current.language = 'fr'
52 User.current.language = 'fr'
51 s1 = "20 f\xc3\xa9vrier 2011"
53 s1 = "20 f\xc3\xa9vrier 2011".force_encoding("UTF-8")
52 s1.force_encoding("UTF-8") if s1.respond_to?(:force_encoding)
53 assert_equal s1, format_date(today)
54 assert_equal s1, format_date(today)
54 User.current.language = nil
55 User.current.language = nil
55 assert_equal '20 Febrero 2011', format_date(today)
56 assert_equal '20 Febrero 2011', format_date(today)
56 end
57 end
58 end
57
59
58 def test_date_and_time_for_each_language
60 def test_date_and_time_for_each_language
59 Setting.date_format = ''
61 with_settings :date_format => '' do
60 valid_languages.each do |lang|
62 valid_languages.each do |lang|
61 set_language_if_valid lang
63 set_language_if_valid lang
62 assert_nothing_raised "#{lang} failure" do
64 assert_nothing_raised "#{lang} failure" do
@@ -75,6 +77,7 class Redmine::I18nTest < ActiveSupport::TestCase
75 assert_equal 13, l('date.month_names').size
77 assert_equal 13, l('date.month_names').size
76 end
78 end
77 end
79 end
80 end
78
81
79 def test_time_for_each_zone
82 def test_time_for_each_zone
80 ActiveSupport::TimeZone.all.each do |zone|
83 ActiveSupport::TimeZone.all.each do |zone|
@@ -134,11 +137,11 class Redmine::I18nTest < ActiveSupport::TestCase
134 def test_utc_time_format
137 def test_utc_time_format
135 set_language_if_valid 'en'
138 set_language_if_valid 'en'
136 now = Time.now
139 now = Time.now
137 Setting.date_format = '%d %m %Y'
140 with_settings :date_format => '%d %m %Y', :time_format => '%H %M' do
138 Setting.time_format = '%H %M'
139 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now.utc)
141 assert_equal now.strftime('%d %m %Y %H %M'), format_time(now.utc)
140 assert_equal now.strftime('%H %M'), format_time(now.utc, false)
142 assert_equal now.strftime('%H %M'), format_time(now.utc, false)
141 end
143 end
144 end
142
145
143 def test_number_to_human_size_for_each_language
146 def test_number_to_human_size_for_each_language
144 valid_languages.each do |lang|
147 valid_languages.each do |lang|
@@ -175,8 +178,7 class Redmine::I18nTest < ActiveSupport::TestCase
175 set_language_if_valid 'bs'
178 set_language_if_valid 'bs'
176 assert_equal "KM -1000,20", number_to_currency(-1000.2)
179 assert_equal "KM -1000,20", number_to_currency(-1000.2)
177 set_language_if_valid 'de'
180 set_language_if_valid 'de'
178 euro_sign = "\xe2\x82\xac"
181 euro_sign = "\xe2\x82\xac".force_encoding('UTF-8')
179 euro_sign.force_encoding('UTF-8') if euro_sign.respond_to?(:force_encoding)
180 assert_equal "-1000,20 #{euro_sign}", number_to_currency(-1000.2)
182 assert_equal "-1000,20 #{euro_sign}", number_to_currency(-1000.2)
181 end
183 end
182
184
@@ -193,8 +195,7 class Redmine::I18nTest < ActiveSupport::TestCase
193 assert_nil options.detect {|option| option.size != 2}
195 assert_nil options.detect {|option| option.size != 2}
194 assert_nil options.detect {|option| !option.first.is_a?(String) || !option.last.is_a?(String)}
196 assert_nil options.detect {|option| !option.first.is_a?(String) || !option.last.is_a?(String)}
195 assert_include ["English", "en"], options
197 assert_include ["English", "en"], options
196 ja = "Japanese (\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e)"
198 ja = "Japanese (\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e)".force_encoding('UTF-8')
197 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
198 assert_include [ja, "ja"], options
199 assert_include [ja, "ja"], options
199 end
200 end
200
201
@@ -238,30 +239,21 class Redmine::I18nTest < ActiveSupport::TestCase
238
239
239 def test_utf8
240 def test_utf8
240 set_language_if_valid 'ja'
241 set_language_if_valid 'ja'
241 str_ja_yes = "\xe3\x81\xaf\xe3\x81\x84"
242 str_ja_yes = "\xe3\x81\xaf\xe3\x81\x84".force_encoding('UTF-8')
242 i18n_ja_yes = l(:general_text_Yes)
243 i18n_ja_yes = l(:general_text_Yes)
243 if str_ja_yes.respond_to?(:force_encoding)
244 str_ja_yes.force_encoding('UTF-8')
245 assert_equal "UTF-8", i18n_ja_yes.encoding.to_s
246 end
247 assert_equal str_ja_yes, i18n_ja_yes
244 assert_equal str_ja_yes, i18n_ja_yes
245 assert_equal "UTF-8", i18n_ja_yes.encoding.to_s
248 end
246 end
249
247
250 def test_traditional_chinese_locale
248 def test_traditional_chinese_locale
251 set_language_if_valid 'zh-TW'
249 set_language_if_valid 'zh-TW'
252 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)"
250 str_tw = "Traditional Chinese (\xe7\xb9\x81\xe9\xab\x94\xe4\xb8\xad\xe6\x96\x87)".force_encoding('UTF-8')
253 if str_tw.respond_to?(:force_encoding)
254 str_tw.force_encoding('UTF-8')
255 end
256 assert_equal str_tw, l(:general_lang_name)
251 assert_equal str_tw, l(:general_lang_name)
257 end
252 end
258
253
259 def test_french_locale
254 def test_french_locale
260 set_language_if_valid 'fr'
255 set_language_if_valid 'fr'
261 str_fr = "Fran\xc3\xa7ais"
256 str_fr = "Fran\xc3\xa7ais".force_encoding('UTF-8')
262 if str_fr.respond_to?(:force_encoding)
263 str_fr.force_encoding('UTF-8')
264 end
265 assert_equal str_fr, l(:general_lang_name)
257 assert_equal str_fr, l(:general_lang_name)
266 end
258 end
267 end
259 end
@@ -16,8 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19 begin
20 require 'mocha/setup'
21
19
22 class BazaarAdapterTest < ActiveSupport::TestCase
20 class BazaarAdapterTest < ActiveSupport::TestCase
23 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
21 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
@@ -218,8 +216,3 begin
218 def test_fake; assert true end
216 def test_fake; assert true end
219 end
217 end
220 end
218 end
221 rescue LoadError
222 class BazaarMochaFake < ActiveSupport::TestCase
223 def test_fake; assert(false, "Requires mocha to run those tests") end
224 end
225 end
@@ -16,8 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19 begin
20 require 'mocha/setup'
21
19
22 class CvsAdapterTest < ActiveSupport::TestCase
20 class CvsAdapterTest < ActiveSupport::TestCase
23 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
21 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
@@ -106,10 +104,3 begin
106 def test_fake; assert true end
104 def test_fake; assert true end
107 end
105 end
108 end
106 end
109
110 rescue LoadError
111 class CvsMochaFake < ActiveSupport::TestCase
112 def test_fake; assert(false, "Requires mocha to run those tests") end
113 end
114 end
115
@@ -16,8 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19 begin
20 require 'mocha/setup'
21
19
22 class DarcsAdapterTest < ActiveSupport::TestCase
20 class DarcsAdapterTest < ActiveSupport::TestCase
23 REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
21 REPOSITORY_PATH = Rails.root.join('tmp/test/darcs_repository').to_s
@@ -60,10 +58,3 begin
60 def test_fake; assert true end
58 def test_fake; assert true end
61 end
59 end
62 end
60 end
63
64 rescue LoadError
65 class DarcsMochaFake < ActiveSupport::TestCase
66 def test_fake; assert(false, "Requires mocha to run those tests") end
67 end
68 end
69
@@ -16,8 +16,6
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19 begin
20 require 'mocha/setup'
21
19
22 class GitAdapterTest < ActiveSupport::TestCase
20 class GitAdapterTest < ActiveSupport::TestCase
23 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
21 REPOSITORY_PATH = Rails.root.join('tmp/test/git_repository').to_s
@@ -60,12 +58,8 begin
60 'ISO-8859-1'
58 'ISO-8859-1'
61 )
59 )
62 assert @adapter
60 assert @adapter
63 @char_1 = CHAR_1_HEX.dup
61 @char_1 = CHAR_1_HEX.dup.force_encoding('UTF-8')
64 @str_felix_hex = FELIX_HEX.dup
62 @str_felix_hex = FELIX_HEX.dup.force_encoding('ASCII-8BIT')
65 if @char_1.respond_to?(:force_encoding)
66 @char_1.force_encoding('UTF-8')
67 @str_felix_hex.force_encoding('ASCII-8BIT')
68 end
69 end
63 end
70
64
71 def test_scm_version
65 def test_scm_version
@@ -601,9 +595,3 begin
601 def test_fake; assert true end
595 def test_fake; assert true end
602 end
596 end
603 end
597 end
604
605 rescue LoadError
606 class GitMochaFake < ActiveSupport::TestCase
607 def test_fake; assert(false, "Requires mocha to run those tests") end
608 end
609 end
@@ -16,15 +16,13
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19 begin
20 require 'mocha/setup'
21
19
22 class MercurialAdapterTest < ActiveSupport::TestCase
20 class MercurialAdapterTest < ActiveSupport::TestCase
23 HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR
21 HELPERS_DIR = Redmine::Scm::Adapters::MercurialAdapter::HELPERS_DIR
24 TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME
22 TEMPLATE_NAME = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_NAME
25 TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION
23 TEMPLATE_EXTENSION = Redmine::Scm::Adapters::MercurialAdapter::TEMPLATE_EXTENSION
26
24
27 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
25 REPOSITORY_PATH = repository_path('mercurial')
28 CHAR_1_HEX = "\xc3\x9c"
26 CHAR_1_HEX = "\xc3\x9c"
29
27
30 if File.directory?(REPOSITORY_PATH)
28 if File.directory?(REPOSITORY_PATH)
@@ -42,16 +40,10 begin
42 nil,
40 nil,
43 'ISO-8859-1')
41 'ISO-8859-1')
44 @diff_c_support = true
42 @diff_c_support = true
45 @char_1 = CHAR_1_HEX.dup
43 @char_1 = CHAR_1_HEX.dup.force_encoding('UTF-8')
46 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
44 @tag_char_1 = "tag-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
47 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
45 @branch_char_0 = "branch-#{CHAR_1_HEX}-00".force_encoding('UTF-8')
48 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
46 @branch_char_1 = "branch-#{CHAR_1_HEX}-01".force_encoding('UTF-8')
49 if @tag_char_1.respond_to?(:force_encoding)
50 @char_1.force_encoding('UTF-8')
51 @tag_char_1.force_encoding('UTF-8')
52 @branch_char_0.force_encoding('UTF-8')
53 @branch_char_1.force_encoding('UTF-8')
54 end
55 end
47 end
56
48
57 def test_hgversion
49 def test_hgversion
@@ -468,8 +460,3 begin
468 def test_fake; assert true end
460 def test_fake; assert true end
469 end
461 end
470 end
462 end
471 rescue LoadError
472 class MercurialMochaFake < ActiveSupport::TestCase
473 def test_fake; assert(false, "Requires mocha to run those tests") end
474 end
475 end
@@ -17,9 +17,6
17
17
18 require File.expand_path('../../../../../../test_helper', __FILE__)
18 require File.expand_path('../../../../../../test_helper', __FILE__)
19
19
20 begin
21 require 'mocha/setup'
22
23 class SubversionAdapterTest < ActiveSupport::TestCase
20 class SubversionAdapterTest < ActiveSupport::TestCase
24
21
25 if repository_configured?('subversion')
22 if repository_configured?('subversion')
@@ -64,8 +61,3 begin
64 def test_fake; assert true end
61 def test_fake; assert true end
65 end
62 end
66 end
63 end
67 rescue LoadError
68 class SubversionMochaFake < ActiveSupport::TestCase
69 def test_fake; assert(false, "Requires mocha to run those tests") end
70 end
71 end
@@ -223,8 +223,7 DIFF
223
223
224 def test_utf8_ja
224 def test_utf8_ja
225 ja = " text_tip_issue_end_day: "
225 ja = " text_tip_issue_end_day: "
226 ja += "\xe3\x81\x93\xe3\x81\xae\xe6\x97\xa5\xe3\x81\xab\xe7\xb5\x82\xe4\xba\x86\xe3\x81\x99\xe3\x82\x8b<span>\xe3\x82\xbf\xe3\x82\xb9\xe3\x82\xaf</span>"
226 ja += "\xe3\x81\x93\xe3\x81\xae\xe6\x97\xa5\xe3\x81\xab\xe7\xb5\x82\xe4\xba\x86\xe3\x81\x99\xe3\x82\x8b<span>\xe3\x82\xbf\xe3\x82\xb9\xe3\x82\xaf</span>".force_encoding('UTF-8')
227 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
228 with_settings :repositories_encodings => '' do
227 with_settings :repositories_encodings => '' do
229 diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ja.diff'), :type => 'inline')
228 diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ja.diff'), :type => 'inline')
230 assert_equal 1, diff.size
229 assert_equal 1, diff.size
@@ -234,8 +233,7 DIFF
234 end
233 end
235
234
236 def test_utf8_ru
235 def test_utf8_ru
237 ru = " other: &quot;\xd0\xbe\xd0\xba\xd0\xbe\xd0\xbb\xd0\xbe %{count} \xd1\x87\xd0\xb0\xd1\x81<span>\xd0\xb0</span>&quot;"
236 ru = " other: &quot;\xd0\xbe\xd0\xba\xd0\xbe\xd0\xbb\xd0\xbe %{count} \xd1\x87\xd0\xb0\xd1\x81<span>\xd0\xb0</span>&quot;".force_encoding('UTF-8')
238 ru.force_encoding('UTF-8') if ru.respond_to?(:force_encoding)
239 with_settings :repositories_encodings => '' do
237 with_settings :repositories_encodings => '' do
240 diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ru.diff'), :type => 'inline')
238 diff = Redmine::UnifiedDiff.new(read_diff_fixture('issue-12641-ru.diff'), :type => 'inline')
241 assert_equal 1, diff.size
239 assert_equal 1, diff.size
@@ -279,10 +277,8 DIFF
279 end
277 end
280
278
281 def test_offset_range_japanese_1
279 def test_offset_range_japanese_1
282 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span></span>"
280 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span></span>".force_encoding('UTF-8')
283 ja1.force_encoding('UTF-8') if ja1.respond_to?(:force_encoding)
281 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x9e</span>".force_encoding('UTF-8')
284 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x9e</span>"
285 ja2.force_encoding('UTF-8') if ja2.respond_to?(:force_encoding)
286 with_settings :repositories_encodings => '' do
282 with_settings :repositories_encodings => '' do
287 diff = Redmine::UnifiedDiff.new(
283 diff = Redmine::UnifiedDiff.new(
288 read_diff_fixture('issue-13644-1.diff'), :type => 'sbs')
284 read_diff_fixture('issue-13644-1.diff'), :type => 'sbs')
@@ -294,10 +290,8 DIFF
294 end
290 end
295
291
296 def test_offset_range_japanese_2
292 def test_offset_range_japanese_2
297 ja1 = "<span></span>\xe6\x97\xa5\xe6\x9c\xac"
293 ja1 = "<span></span>\xe6\x97\xa5\xe6\x9c\xac".force_encoding('UTF-8')
298 ja1.force_encoding('UTF-8') if ja1.respond_to?(:force_encoding)
294 ja2 = "<span>\xe3\x81\xab\xe3\x81\xa3\xe3\x81\xbd\xe3\x82\x93</span>\xe6\x97\xa5\xe6\x9c\xac".force_encoding('UTF-8')
299 ja2 = "<span>\xe3\x81\xab\xe3\x81\xa3\xe3\x81\xbd\xe3\x82\x93</span>\xe6\x97\xa5\xe6\x9c\xac"
300 ja2.force_encoding('UTF-8') if ja2.respond_to?(:force_encoding)
301 with_settings :repositories_encodings => '' do
295 with_settings :repositories_encodings => '' do
302 diff = Redmine::UnifiedDiff.new(
296 diff = Redmine::UnifiedDiff.new(
303 read_diff_fixture('issue-13644-2.diff'), :type => 'sbs')
297 read_diff_fixture('issue-13644-2.diff'), :type => 'sbs')
@@ -310,10 +304,8 DIFF
310
304
311 def test_offset_range_japanese_3
305 def test_offset_range_japanese_3
312 # UTF-8 The 1st byte differs.
306 # UTF-8 The 1st byte differs.
313 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>"
307 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>".force_encoding('UTF-8')
314 ja1.force_encoding('UTF-8') if ja1.respond_to?(:force_encoding)
308 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe5\xa8\x98</span>".force_encoding('UTF-8')
315 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe5\xa8\x98</span>"
316 ja2.force_encoding('UTF-8') if ja2.respond_to?(:force_encoding)
317 with_settings :repositories_encodings => '' do
309 with_settings :repositories_encodings => '' do
318 diff = Redmine::UnifiedDiff.new(
310 diff = Redmine::UnifiedDiff.new(
319 read_diff_fixture('issue-13644-3.diff'), :type => 'sbs')
311 read_diff_fixture('issue-13644-3.diff'), :type => 'sbs')
@@ -326,10 +318,8 DIFF
326
318
327 def test_offset_range_japanese_4
319 def test_offset_range_japanese_4
328 # UTF-8 The 2nd byte differs.
320 # UTF-8 The 2nd byte differs.
329 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>"
321 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>".force_encoding('UTF-8')
330 ja1.force_encoding('UTF-8') if ja1.respond_to?(:force_encoding)
322 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>".force_encoding('UTF-8')
331 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>"
332 ja2.force_encoding('UTF-8') if ja2.respond_to?(:force_encoding)
333 with_settings :repositories_encodings => '' do
323 with_settings :repositories_encodings => '' do
334 diff = Redmine::UnifiedDiff.new(
324 diff = Redmine::UnifiedDiff.new(
335 read_diff_fixture('issue-13644-4.diff'), :type => 'sbs')
325 read_diff_fixture('issue-13644-4.diff'), :type => 'sbs')
@@ -342,10 +332,8 DIFF
342
332
343 def test_offset_range_japanese_5
333 def test_offset_range_japanese_5
344 # UTF-8 The 2nd byte differs.
334 # UTF-8 The 2nd byte differs.
345 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>ok"
335 ja1 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xa8\x98</span>ok".force_encoding('UTF-8')
346 ja1.force_encoding('UTF-8') if ja1.respond_to?(:force_encoding)
336 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>ok".force_encoding('UTF-8')
347 ja2 = "\xe6\x97\xa5\xe6\x9c\xac<span>\xe8\xaa\x98</span>ok"
348 ja2.force_encoding('UTF-8') if ja2.respond_to?(:force_encoding)
349 with_settings :repositories_encodings => '' do
337 with_settings :repositories_encodings => '' do
350 diff = Redmine::UnifiedDiff.new(
338 diff = Redmine::UnifiedDiff.new(
351 read_diff_fixture('issue-13644-5.diff'), :type => 'sbs')
339 read_diff_fixture('issue-13644-5.diff'), :type => 'sbs')
@@ -207,6 +207,7 class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase
207
207
208 def test_macro_collapse
208 def test_macro_collapse
209 text = "{{collapse\n*Collapsed* block of text\n}}"
209 text = "{{collapse\n*Collapsed* block of text\n}}"
210 with_locale 'en' do
210 result = textilizable(text)
211 result = textilizable(text)
211
212
212 assert_select_in result, 'div.collapsed-text'
213 assert_select_in result, 'div.collapsed-text'
@@ -214,6 +215,7 class Redmine::WikiFormatting::MacrosTest < ActionView::TestCase
214 assert_select_in result, 'a.collapsible.collapsed', :text => 'Show'
215 assert_select_in result, 'a.collapsible.collapsed', :text => 'Show'
215 assert_select_in result, 'a.collapsible', :text => 'Hide'
216 assert_select_in result, 'a.collapsible', :text => 'Hide'
216 end
217 end
218 end
217
219
218 def test_macro_collapse_with_one_arg
220 def test_macro_collapse_with_one_arg
219 text = "{{collapse(Example)\n*Collapsed* block of text\n}}"
221 text = "{{collapse(Example)\n*Collapsed* block of text\n}}"
@@ -411,8 +411,7 class MailHandlerTest < ActiveSupport::TestCase
411 end
411 end
412
412
413 def test_add_issue_with_japanese_keywords
413 def test_add_issue_with_japanese_keywords
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba"
414 ja_dev = "\xe9\x96\x8b\xe7\x99\xba".force_encoding('UTF-8')
415 ja_dev.force_encoding('UTF-8') if ja_dev.respond_to?(:force_encoding)
416 tracker = Tracker.create!(:name => ja_dev)
415 tracker = Tracker.create!(:name => ja_dev)
417 Project.find(1).trackers << tracker
416 Project.find(1).trackers << tracker
418 issue = submit_email(
417 issue = submit_email(
@@ -447,8 +446,7 class MailHandlerTest < ActiveSupport::TestCase
447 )
446 )
448 assert_kind_of Issue, issue
447 assert_kind_of Issue, issue
449 assert_equal 1, issue.attachments.size
448 assert_equal 1, issue.attachments.size
450 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
449 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
451 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
452 attachment = issue.attachments.first
450 attachment = issue.attachments.first
453 assert_equal ja, attachment.filename
451 assert_equal ja, attachment.filename
454 assert_equal 5, attachment.filesize
452 assert_equal 5, attachment.filesize
@@ -464,8 +462,7 class MailHandlerTest < ActiveSupport::TestCase
464 )
462 )
465 assert_kind_of Issue, issue
463 assert_kind_of Issue, issue
466 assert_equal 1, issue.attachments.size
464 assert_equal 1, issue.attachments.size
467 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt"
465 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88.txt".force_encoding('UTF-8')
468 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
469 attachment = issue.attachments.first
466 attachment = issue.attachments.first
470 assert_equal ja, attachment.filename
467 assert_equal ja, attachment.filename
471 assert_equal 5, attachment.filesize
468 assert_equal 5, attachment.filesize
@@ -481,10 +478,8 class MailHandlerTest < ActiveSupport::TestCase
481 )
478 )
482 assert_kind_of Issue, issue
479 assert_kind_of Issue, issue
483 assert_equal 1, issue.attachments.size
480 assert_equal 1, issue.attachments.size
484 u = ""
481 u = "".force_encoding('UTF-8')
485 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
482 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
486 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
487 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
488 11.times { u << u1 }
483 11.times { u << u1 }
489 attachment = issue.attachments.first
484 attachment = issue.attachments.first
490 assert_equal "#{u}.png", attachment.filename
485 assert_equal "#{u}.png", attachment.filename
@@ -501,10 +496,8 class MailHandlerTest < ActiveSupport::TestCase
501 )
496 )
502 assert_kind_of Issue, issue
497 assert_kind_of Issue, issue
503 assert_equal 1, issue.attachments.size
498 assert_equal 1, issue.attachments.size
504 u = ""
499 u = "".force_encoding('UTF-8')
505 u.force_encoding('UTF-8') if u.respond_to?(:force_encoding)
500 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc".force_encoding('UTF-8')
506 u1 = "\xc3\x84\xc3\xa4\xc3\x96\xc3\xb6\xc3\x9c\xc3\xbc"
507 u1.force_encoding('UTF-8') if u1.respond_to?(:force_encoding)
508 11.times { u << u1 }
501 11.times { u << u1 }
509 attachment = issue.attachments.first
502 attachment = issue.attachments.first
510 assert_equal "#{u}.txt", attachment.filename
503 assert_equal "#{u}.txt", attachment.filename
@@ -534,8 +527,7 class MailHandlerTest < ActiveSupport::TestCase
534 'subject_as_iso-8859-1.eml',
527 'subject_as_iso-8859-1.eml',
535 :issue => {:project => 'ecookbook'}
528 :issue => {:project => 'ecookbook'}
536 )
529 )
537 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc..."
530 str = "Testmail from Webmail: \xc3\xa4 \xc3\xb6 \xc3\xbc...".force_encoding('UTF-8')
538 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
539 assert_kind_of Issue, issue
531 assert_kind_of Issue, issue
540 assert_equal str, issue.subject
532 assert_equal str, issue.subject
541 end
533 end
@@ -546,8 +538,7 class MailHandlerTest < ActiveSupport::TestCase
546 :issue => {:project => 'ecookbook'}
538 :issue => {:project => 'ecookbook'}
547 )
539 )
548 assert_kind_of Issue, issue
540 assert_kind_of Issue, issue
549 str = "Freundliche Gr\xc3\xbcsse"
541 str = "Freundliche Gr\xc3\xbcsse".force_encoding('UTF-8')
550 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
551 assert_equal str, issue.description
542 assert_equal str, issue.description
552 end
543 end
553
544
@@ -557,8 +548,7 class MailHandlerTest < ActiveSupport::TestCase
557 :issue => {:project => 'ecookbook'}
548 :issue => {:project => 'ecookbook'}
558 )
549 )
559 assert_kind_of Issue, issue
550 assert_kind_of Issue, issue
560 str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87."
551 str = "Na \xc5\xa1triku se su\xc5\xa1i \xc5\xa1osi\xc4\x87.".force_encoding('UTF-8')
561 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
562 assert issue.description.include?(str)
552 assert issue.description.include?(str)
563 end
553 end
564
554
@@ -568,19 +558,14 class MailHandlerTest < ActiveSupport::TestCase
568 :issue => {:project => 'ecookbook'}
558 :issue => {:project => 'ecookbook'}
569 )
559 )
570 assert_kind_of Issue, issue
560 assert_kind_of Issue, issue
571 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
561 ja = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
572 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
573 assert_equal ja, issue.subject
562 assert_equal ja, issue.subject
574 end
563 end
575
564
576 def test_add_issue_with_korean_body
565 def test_add_issue_with_korean_body
577 # Make sure mail bodies with a charset unknown to Ruby
566 # Make sure mail bodies with a charset unknown to Ruby
578 # but known to the Mail gem 2.5.4 are handled correctly
567 # but known to the Mail gem 2.5.4 are handled correctly
579 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4."
568 kr = "\xEA\xB3\xA0\xEB\xA7\x99\xEC\x8A\xB5\xEB\x8B\x88\xEB\x8B\xA4.".force_encoding('UTF-8')
580 if !kr.respond_to?(:force_encoding)
581 puts "\nOn Ruby 1.8, skip Korean encoding mail body test"
582 else
583 kr.force_encoding('UTF-8')
584 issue = submit_email(
569 issue = submit_email(
585 'body_ks_c_5601-1987.eml',
570 'body_ks_c_5601-1987.eml',
586 :issue => {:project => 'ecookbook'}
571 :issue => {:project => 'ecookbook'}
@@ -588,7 +573,6 class MailHandlerTest < ActiveSupport::TestCase
588 assert_kind_of Issue, issue
573 assert_kind_of Issue, issue
589 assert_equal kr, issue.description
574 assert_equal kr, issue.description
590 end
575 end
591 end
592
576
593 def test_add_issue_with_no_subject_header
577 def test_add_issue_with_no_subject_header
594 issue = submit_email(
578 issue = submit_email(
@@ -605,8 +589,7 class MailHandlerTest < ActiveSupport::TestCase
605 :issue => {:project => 'ecookbook'}
589 :issue => {:project => 'ecookbook'}
606 )
590 )
607 assert_kind_of Issue, issue
591 assert_kind_of Issue, issue
608 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
592 ja = "Re: \xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
609 ja.force_encoding('UTF-8') if ja.respond_to?(:force_encoding)
610 assert_equal ja, issue.subject
593 assert_equal ja, issue.subject
611 end
594 end
612
595
@@ -910,10 +893,8 class MailHandlerTest < ActiveSupport::TestCase
910 end
893 end
911 user = User.order('id DESC').first
894 user = User.order('id DESC').first
912 assert_equal "foo@example.org", user.mail
895 assert_equal "foo@example.org", user.mail
913 str1 = "\xc3\x84\xc3\xa4"
896 str1 = "\xc3\x84\xc3\xa4".force_encoding('UTF-8')
914 str2 = "\xc3\x96\xc3\xb6"
897 str2 = "\xc3\x96\xc3\xb6".force_encoding('UTF-8')
915 str1.force_encoding('UTF-8') if str1.respond_to?(:force_encoding)
916 str2.force_encoding('UTF-8') if str2.respond_to?(:force_encoding)
917 assert_equal str1, user.firstname
898 assert_equal str1, user.firstname
918 assert_equal str2, user.lastname
899 assert_equal str2, user.lastname
919 end
900 end
@@ -34,6 +34,7 class MailerTest < ActiveSupport::TestCase
34 Setting.host_name = 'mydomain.foo'
34 Setting.host_name = 'mydomain.foo'
35 Setting.protocol = 'http'
35 Setting.protocol = 'http'
36 Setting.plain_text_mail = '0'
36 Setting.plain_text_mail = '0'
37 User.current = nil
37 end
38 end
38
39
39 def test_generated_links_in_emails
40 def test_generated_links_in_emails
@@ -79,9 +79,8 class MemberTest < ActiveSupport::TestCase
79 member = Member.new(:project_id => 1, :user_id => user.id, :role_ids => [])
79 member = Member.new(:project_id => 1, :user_id => user.id, :role_ids => [])
80 assert !member.save
80 assert !member.save
81 assert_include I18n.translate('activerecord.errors.messages.empty'), member.errors[:role]
81 assert_include I18n.translate('activerecord.errors.messages.empty'), member.errors[:role]
82 str = "R\xc3\xb4le doit \xc3\xaatre renseign\xc3\xa9(e)"
82 assert_equal "R\xc3\xb4le doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8'),
83 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
83 [member.errors.full_messages].flatten.join
84 assert_equal str, [member.errors.full_messages].flatten.join
85 end
84 end
86
85
87 def test_validate_member_role
86 def test_validate_member_role
@@ -131,7 +130,7 class MemberTest < ActiveSupport::TestCase
131 end
130 end
132 assert m.destroyed?
131 assert m.destroyed?
133 ensure
132 ensure
134 Member._destroy_callbacks.reject! {|c| c.filter==:destroy_test_callback}
133 Member._destroy_callbacks.delete(:destroy_test_callback)
135 end
134 end
136
135
137 def test_sort_without_roles
136 def test_sort_without_roles
@@ -23,7 +23,7 class PrincipalTest < ActiveSupport::TestCase
23 fixtures :users, :projects, :members, :member_roles
23 fixtures :users, :projects, :members, :member_roles
24
24
25 def test_active_scope_should_return_groups_and_active_users
25 def test_active_scope_should_return_groups_and_active_users
26 result = Principal.active.all
26 result = Principal.active.to_a
27 assert_include Group.first, result
27 assert_include Group.first, result
28 assert_not_nil result.detect {|p| p.is_a?(User)}
28 assert_not_nil result.detect {|p| p.is_a?(User)}
29 assert_nil result.detect {|p| p.is_a?(User) && !p.active?}
29 assert_nil result.detect {|p| p.is_a?(User) && !p.active?}
@@ -222,17 +222,6 class ProjectCopyTest < ActiveSupport::TestCase
222 assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
222 assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
223 end
223 end
224
224
225 def test_copy_should_copy_queries_roles_visibility
226 source = Project.generate!
227 target = Project.new(:name => 'Copy Test', :identifier => 'copy-test')
228 IssueQuery.generate!(:project => source, :visibility => Query::VISIBILITY_ROLES, :roles => Role.where(:id => [1, 3]).to_a)
229
230 assert target.copy(source)
231 assert_equal 1, target.queries.size
232 query = target.queries.first
233 assert_equal [1, 3], query.role_ids.sort
234 end
235
236 test "#copy should copy versions" do
225 test "#copy should copy versions" do
237 @source_project.versions << Version.generate!
226 @source_project.versions << Version.generate!
238 @source_project.versions << Version.generate!
227 @source_project.versions << Version.generate!
@@ -61,6 +61,11 class ProjectNestedSetTest < ActiveSupport::TestCase
61 assert_valid_nested_set
61 assert_valid_nested_set
62 end
62 end
63
63
64 def test_rebuild_without_projects_should_not_fail
65 Project.delete_all
66 assert Project.rebuild_tree!
67 end
68
64 def test_moving_a_child_to_a_different_parent_should_keep_valid_tree
69 def test_moving_a_child_to_a_different_parent_should_keep_valid_tree
65 assert_no_difference 'Project.count' do
70 assert_no_difference 'Project.count' do
66 Project.find_by_name('B1').set_parent!(Project.find_by_name('A2'))
71 Project.find_by_name('B1').set_parent!(Project.find_by_name('A2'))
@@ -316,7 +316,7 class ProjectTest < ActiveSupport::TestCase
316
316
317 parent.reload
317 parent.reload
318 assert_equal 4, parent.children.size
318 assert_equal 4, parent.children.size
319 assert_equal parent.children.all.sort_by(&:name), parent.children.all
319 assert_equal parent.children.sort_by(&:name), parent.children.to_a
320 end
320 end
321
321
322 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
322 def test_set_parent_should_update_issue_fixed_version_associations_when_a_fixed_version_is_moved_out_of_the_hierarchy
@@ -729,7 +729,7 class ProjectTest < ActiveSupport::TestCase
729
729
730 def test_activities_should_use_the_system_activities
730 def test_activities_should_use_the_system_activities
731 project = Project.find(1)
731 project = Project.find(1)
732 assert_equal project.activities, TimeEntryActivity.where(:active => true).all
732 assert_equal project.activities.to_a, TimeEntryActivity.where(:active => true).to_a
733 assert_kind_of ActiveRecord::Relation, project.activities
733 assert_kind_of ActiveRecord::Relation, project.activities
734 end
734 end
735
735
@@ -944,4 +944,10 class ProjectTest < ActiveSupport::TestCase
944 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
944 assert !project.notified_users.include?(only_assigned_user), "should not include users with the 'only_assigned' notification option"
945 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
945 assert !project.notified_users.include?(only_owned_user), "should not include users with the 'only_owner' notification option"
946 end
946 end
947
948 def test_override_roles_without_builtin_group_memberships
949 project = Project.generate!
950 assert_equal [Role.anonymous], project.override_roles(Role.anonymous)
951 assert_equal [Role.non_member], project.override_roles(Role.non_member)
952 end
947 end
953 end
@@ -101,9 +101,9 class QueryTest < ActiveSupport::TestCase
101 end
101 end
102
102
103 def find_issues_with_query(query)
103 def find_issues_with_query(query)
104 Issue.includes([:assigned_to, :status, :tracker, :project, :priority]).where(
104 Issue.joins(:status, :tracker, :project, :priority).where(
105 query.statement
105 query.statement
106 ).all
106 ).references([:assigned_to, :status, :tracker, :project, :priority]).to_a
107 end
107 end
108
108
109 def assert_find_issues_with_query_is_successful(query)
109 def assert_find_issues_with_query_is_successful(query)
@@ -1118,9 +1118,7 class QueryTest < ActiveSupport::TestCase
1118 def test_label_for_fr
1118 def test_label_for_fr
1119 set_language_if_valid 'fr'
1119 set_language_if_valid 'fr'
1120 q = IssueQuery.new
1120 q = IssueQuery.new
1121 s = "Assign\xc3\xa9 \xc3\xa0"
1121 assert_equal "Assign\xc3\xa9 \xc3\xa0".force_encoding('UTF-8'), q.label_for('assigned_to_id')
1122 s.force_encoding('UTF-8') if s.respond_to?(:force_encoding)
1123 assert_equal s, q.label_for('assigned_to_id')
1124 end
1122 end
1125
1123
1126 def test_editable_by
1124 def test_editable_by
@@ -22,7 +22,7 class RepositoryBazaarTest < ActiveSupport::TestCase
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/bazaar_repository').to_s
25 REPOSITORY_PATH = repository_path('bazaar')
26 REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
26 REPOSITORY_PATH_TRUNK = File.join(REPOSITORY_PATH, "trunk")
27 NUM_REV = 4
27 NUM_REV = 4
28
28
@@ -42,11 +42,10 class RepositoryBazaarTest < ActiveSupport::TestCase
42 # you cannot run Bazaar non ASCII path tests.
42 # you cannot run Bazaar non ASCII path tests.
43 #
43 #
44 RUN_LATIN1_OUTPUT_TEST = (RUBY_PLATFORM != 'java' &&
44 RUN_LATIN1_OUTPUT_TEST = (RUBY_PLATFORM != 'java' &&
45 REPOSITORY_PATH.respond_to?(:force_encoding) &&
46 Encoding.locale_charmap == "ISO-8859-1")
45 Encoding.locale_charmap == "ISO-8859-1")
47
46
48 CHAR_1_UTF8_HEX = "\xc3\x9c"
47 CHAR_1_UTF8_HEX = "\xc3\x9c".force_encoding('UTF-8')
49 CHAR_1_LATIN1_HEX = "\xdc"
48 CHAR_1_LATIN1_HEX = "\xdc".force_encoding('ASCII-8BIT')
50
49
51 def setup
50 def setup
52 @project = Project.find(3)
51 @project = Project.find(3)
@@ -54,12 +53,6 class RepositoryBazaarTest < ActiveSupport::TestCase
54 :project => @project, :url => REPOSITORY_PATH_TRUNK,
53 :project => @project, :url => REPOSITORY_PATH_TRUNK,
55 :log_encoding => 'UTF-8')
54 :log_encoding => 'UTF-8')
56 assert @repository
55 assert @repository
57 @char_1_utf8 = CHAR_1_UTF8_HEX.dup
58 @char_1_ascii8bit = CHAR_1_LATIN1_HEX.dup
59 if @char_1_utf8.respond_to?(:force_encoding)
60 @char_1_utf8.force_encoding('UTF-8')
61 @char_1_ascii8bit.force_encoding('ASCII-8BIT')
62 end
63 end
56 end
64
57
65 def test_blank_path_to_repository_error_message
58 def test_blank_path_to_repository_error_message
@@ -76,8 +69,7 class RepositoryBazaarTest < ActiveSupport::TestCase
76
69
77 def test_blank_path_to_repository_error_message_fr
70 def test_blank_path_to_repository_error_message_fr
78 set_language_if_valid 'fr'
71 set_language_if_valid 'fr'
79 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
72 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
80 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
81 repo = Repository::Bazaar.new(
73 repo = Repository::Bazaar.new(
82 :project => @project,
74 :project => @project,
83 :url => "",
75 :url => "",
@@ -178,70 +170,70 class RepositoryBazaarTest < ActiveSupport::TestCase
178 def test_cat_latin1_path
170 def test_cat_latin1_path
179 latin1_repo = create_latin1_repo
171 latin1_repo = create_latin1_repo
180 buf = latin1_repo.cat(
172 buf = latin1_repo.cat(
181 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", 2)
173 "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-2.txt", 2)
182 assert buf
174 assert buf
183 lines = buf.split("\n")
175 lines = buf.split("\n")
184 assert_equal 2, lines.length
176 assert_equal 2, lines.length
185 assert_equal 'It is written in Python.', lines[1]
177 assert_equal 'It is written in Python.', lines[1]
186
178
187 buf = latin1_repo.cat(
179 buf = latin1_repo.cat(
188 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2)
180 "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt", 2)
189 assert buf
181 assert buf
190 lines = buf.split("\n")
182 lines = buf.split("\n")
191 assert_equal 1, lines.length
183 assert_equal 1, lines.length
192 assert_equal "test-#{@char_1_ascii8bit}.txt", lines[0]
184 assert_equal "test-#{CHAR_1_LATIN1_HEX}.txt", lines[0]
193 end
185 end
194
186
195 def test_annotate_latin1_path
187 def test_annotate_latin1_path
196 latin1_repo = create_latin1_repo
188 latin1_repo = create_latin1_repo
197 ann1 = latin1_repo.annotate(
189 ann1 = latin1_repo.annotate(
198 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", 2)
190 "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-2.txt", 2)
199 assert_equal 2, ann1.lines.size
191 assert_equal 2, ann1.lines.size
200 assert_equal '2', ann1.revisions[0].identifier
192 assert_equal '2', ann1.revisions[0].identifier
201 assert_equal 'test00@', ann1.revisions[0].author
193 assert_equal 'test00@', ann1.revisions[0].author
202 assert_equal 'It is written in Python.', ann1.lines[1]
194 assert_equal 'It is written in Python.', ann1.lines[1]
203 ann2 = latin1_repo.annotate(
195 ann2 = latin1_repo.annotate(
204 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2)
196 "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt", 2)
205 assert_equal 1, ann2.lines.size
197 assert_equal 1, ann2.lines.size
206 assert_equal '2', ann2.revisions[0].identifier
198 assert_equal '2', ann2.revisions[0].identifier
207 assert_equal 'test00@', ann2.revisions[0].author
199 assert_equal 'test00@', ann2.revisions[0].author
208 assert_equal "test-#{@char_1_ascii8bit}.txt", ann2.lines[0]
200 assert_equal "test-#{CHAR_1_LATIN1_HEX}.txt", ann2.lines[0]
209 end
201 end
210
202
211 def test_diff_latin1_path
203 def test_diff_latin1_path
212 latin1_repo = create_latin1_repo
204 latin1_repo = create_latin1_repo
213 diff1 = latin1_repo.diff(
205 diff1 = latin1_repo.diff(
214 "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", 2, 1)
206 "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt", 2, 1)
215 assert_equal 7, diff1.size
207 assert_equal 7, diff1.size
216 buf = diff1[5].gsub(/\r\n|\r|\n/, "")
208 buf = diff1[5].gsub(/\r\n|\r|\n/, "")
217 assert_equal "+test-#{@char_1_ascii8bit}.txt", buf
209 assert_equal "+test-#{CHAR_1_LATIN1_HEX}.txt", buf
218 end
210 end
219
211
220 def test_entries_latin1_path
212 def test_entries_latin1_path
221 latin1_repo = create_latin1_repo
213 latin1_repo = create_latin1_repo
222 entries = latin1_repo.entries("test-#{@char_1_utf8}-dir", 2)
214 entries = latin1_repo.entries("test-#{CHAR_1_UTF8_HEX}-dir", 2)
223 assert_kind_of Redmine::Scm::Adapters::Entries, entries
215 assert_kind_of Redmine::Scm::Adapters::Entries, entries
224 assert_equal 3, entries.size
216 assert_equal 3, entries.size
225 assert_equal 'file', entries[1].kind
217 assert_equal 'file', entries[1].kind
226 assert_equal "test-#{@char_1_utf8}-1.txt", entries[0].name
218 assert_equal "test-#{CHAR_1_UTF8_HEX}-1.txt", entries[0].name
227 assert_equal "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", entries[0].path
219 assert_equal "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt", entries[0].path
228 end
220 end
229
221
230 def test_entry_latin1_path
222 def test_entry_latin1_path
231 latin1_repo = create_latin1_repo
223 latin1_repo = create_latin1_repo
232 ["test-#{@char_1_utf8}-dir",
224 ["test-#{CHAR_1_UTF8_HEX}-dir",
233 "/test-#{@char_1_utf8}-dir",
225 "/test-#{CHAR_1_UTF8_HEX}-dir",
234 "/test-#{@char_1_utf8}-dir/"
226 "/test-#{CHAR_1_UTF8_HEX}-dir/"
235 ].each do |path|
227 ].each do |path|
236 entry = latin1_repo.entry(path, 2)
228 entry = latin1_repo.entry(path, 2)
237 assert_equal "test-#{@char_1_utf8}-dir", entry.path
229 assert_equal "test-#{CHAR_1_UTF8_HEX}-dir", entry.path
238 assert_equal "dir", entry.kind
230 assert_equal "dir", entry.kind
239 end
231 end
240 ["test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt",
232 ["test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt",
241 "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt"
233 "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt"
242 ].each do |path|
234 ].each do |path|
243 entry = latin1_repo.entry(path, 2)
235 entry = latin1_repo.entry(path, 2)
244 assert_equal "test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt",
236 assert_equal "test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt",
245 entry.path
237 entry.path
246 assert_equal "file", entry.kind
238 assert_equal "file", entry.kind
247 end
239 end
@@ -256,35 +248,33 class RepositoryBazaarTest < ActiveSupport::TestCase
256
248
257 cs2 = latin1_repo.changesets.find_by_revision('2')
249 cs2 = latin1_repo.changesets.find_by_revision('2')
258 assert_not_nil cs2
250 assert_not_nil cs2
259 assert_equal "test-#{@char_1_utf8}", cs2.comments
251 assert_equal "test-#{CHAR_1_UTF8_HEX}", cs2.comments
260 c2 = cs2.filechanges.sort_by(&:path)
252 c2 = cs2.filechanges.sort_by(&:path)
261 assert_equal 4, c2.size
253 assert_equal 4, c2.size
262 assert_equal 'A', c2[0].action
254 assert_equal 'A', c2[0].action
263 assert_equal "/test-#{@char_1_utf8}-dir/", c2[0].path
255 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/", c2[0].path
264 assert_equal 'A', c2[1].action
256 assert_equal 'A', c2[1].action
265 assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-1.txt", c2[1].path
257 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-1.txt", c2[1].path
266 assert_equal 'A', c2[2].action
258 assert_equal 'A', c2[2].action
267 assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", c2[2].path
259 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-2.txt", c2[2].path
268 assert_equal 'A', c2[3].action
260 assert_equal 'A', c2[3].action
269 assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}.txt", c2[3].path
261 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}.txt", c2[3].path
270
262
271 cs3 = latin1_repo.changesets.find_by_revision('3')
263 cs3 = latin1_repo.changesets.find_by_revision('3')
272 assert_not_nil cs3
264 assert_not_nil cs3
273 assert_equal "modify, move and delete #{@char_1_utf8} files", cs3.comments
265 assert_equal "modify, move and delete #{CHAR_1_UTF8_HEX} files", cs3.comments
274 c3 = cs3.filechanges.sort_by(&:path)
266 c3 = cs3.filechanges.sort_by(&:path)
275 assert_equal 3, c3.size
267 assert_equal 3, c3.size
276 assert_equal 'M', c3[0].action
268 assert_equal 'M', c3[0].action
277 assert_equal "/test-#{@char_1_utf8}-1.txt", c3[0].path
269 assert_equal "/test-#{CHAR_1_UTF8_HEX}-1.txt", c3[0].path
278 assert_equal 'D', c3[1].action
270 assert_equal 'D', c3[1].action
279 assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}-2.txt", c3[1].path
271 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}-2.txt", c3[1].path
280 assert_equal 'M', c3[2].action
272 assert_equal 'M', c3[2].action
281 assert_equal "/test-#{@char_1_utf8}-dir/test-#{@char_1_utf8}.txt", c3[2].path
273 assert_equal "/test-#{CHAR_1_UTF8_HEX}-dir/test-#{CHAR_1_UTF8_HEX}.txt", c3[2].path
282 end
274 end
283 else
275 else
284 msg = "Bazaar non ASCII output test cannot run this environment." + "\n"
276 msg = "Bazaar non ASCII output test cannot run this environment.\n"
285 if msg.respond_to?(:force_encoding)
286 msg += "Encoding.locale_charmap: " + Encoding.locale_charmap + "\n"
277 msg += "Encoding.locale_charmap: " + Encoding.locale_charmap + "\n"
287 end
288 puts msg
278 puts msg
289 end
279 end
290
280
@@ -22,7 +22,7 class RepositoryCvsTest < ActiveSupport::TestCase
22
22
23 include Redmine::I18n
23 include Redmine::I18n
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/cvs_repository').to_s
25 REPOSITORY_PATH = repository_path('cvs')
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
26 REPOSITORY_PATH.gsub!(/\//, "\\") if Redmine::Platform.mswin?
27 # CVS module
27 # CVS module
28 MODULE_NAME = 'test'
28 MODULE_NAME = 'test'
@@ -52,8 +52,7 class RepositoryCvsTest < ActiveSupport::TestCase
52
52
53 def test_blank_module_error_message_fr
53 def test_blank_module_error_message_fr
54 set_language_if_valid 'fr'
54 set_language_if_valid 'fr'
55 str = "Module doit \xc3\xaatre renseign\xc3\xa9(e)"
55 str = "Module doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
56 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
57 repo = Repository::Cvs.new(
56 repo = Repository::Cvs.new(
58 :project => @project,
57 :project => @project,
59 :identifier => 'test',
58 :identifier => 'test',
@@ -81,8 +80,7 class RepositoryCvsTest < ActiveSupport::TestCase
81
80
82 def test_blank_cvsroot_error_message_fr
81 def test_blank_cvsroot_error_message_fr
83 set_language_if_valid 'fr'
82 set_language_if_valid 'fr'
84 str = "CVSROOT doit \xc3\xaatre renseign\xc3\xa9(e)"
83 str = "CVSROOT doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
85 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
86 repo = Repository::Cvs.new(
84 repo = Repository::Cvs.new(
87 :project => @project,
85 :project => @project,
88 :identifier => 'test',
86 :identifier => 'test',
@@ -49,8 +49,7 class RepositoryDarcsTest < ActiveSupport::TestCase
49
49
50 def test_blank_path_to_repository_error_message_fr
50 def test_blank_path_to_repository_error_message_fr
51 set_language_if_valid 'fr'
51 set_language_if_valid 'fr'
52 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
52 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
53 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
54 repo = Repository::Darcs.new(
53 repo = Repository::Darcs.new(
55 :project => @project,
54 :project => @project,
56 :url => "",
55 :url => "",
@@ -47,8 +47,7 class RepositoryFilesystemTest < ActiveSupport::TestCase
47
47
48 def test_blank_root_directory_error_message_fr
48 def test_blank_root_directory_error_message_fr
49 set_language_if_valid 'fr'
49 set_language_if_valid 'fr'
50 str = "R\xc3\xa9pertoire racine doit \xc3\xaatre renseign\xc3\xa9(e)"
50 str = "R\xc3\xa9pertoire racine doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
51 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
52 repo = Repository::Filesystem.new(
51 repo = Repository::Filesystem.new(
53 :project => @project,
52 :project => @project,
54 :url => "",
53 :url => "",
@@ -28,8 +28,8 class RepositoryGitTest < ActiveSupport::TestCase
28 NUM_REV = 28
28 NUM_REV = 28
29 NUM_HEAD = 6
29 NUM_HEAD = 6
30
30
31 FELIX_HEX = "Felix Sch\xC3\xA4fer"
31 FELIX_HEX = "Felix Sch\xC3\xA4fer".force_encoding('UTF-8')
32 CHAR_1_HEX = "\xc3\x9c"
32 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
33
33
34 ## Git, Mercurial and CVS path encodings are binary.
34 ## Git, Mercurial and CVS path encodings are binary.
35 ## Subversion supports URL encoding for path.
35 ## Subversion supports URL encoding for path.
@@ -47,10 +47,6 class RepositoryGitTest < ActiveSupport::TestCase
47 :path_encoding => 'ISO-8859-1'
47 :path_encoding => 'ISO-8859-1'
48 )
48 )
49 assert @repository
49 assert @repository
50 @char_1 = CHAR_1_HEX.dup
51 if @char_1.respond_to?(:force_encoding)
52 @char_1.force_encoding('UTF-8')
53 end
54 end
50 end
55
51
56 def test_blank_path_to_repository_error_message
52 def test_blank_path_to_repository_error_message
@@ -66,8 +62,7 class RepositoryGitTest < ActiveSupport::TestCase
66
62
67 def test_blank_path_to_repository_error_message_fr
63 def test_blank_path_to_repository_error_message_fr
68 set_language_if_valid 'fr'
64 set_language_if_valid 'fr'
69 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
65 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
70 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
71 repo = Repository::Git.new(
66 repo = Repository::Git.new(
72 :project => @project,
67 :project => @project,
73 :url => "",
68 :url => "",
@@ -450,14 +445,14 class RepositoryGitTest < ActiveSupport::TestCase
450 else
445 else
451 # latin-1 encoding path
446 # latin-1 encoding path
452 changesets = @repository.latest_changesets(
447 changesets = @repository.latest_changesets(
453 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89')
448 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89')
454 assert_equal [
449 assert_equal [
455 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
450 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
456 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
451 '4fc55c43bf3d3dc2efb66145365ddc17639ce81e',
457 ], changesets.collect(&:revision)
452 ], changesets.collect(&:revision)
458
453
459 changesets = @repository.latest_changesets(
454 changesets = @repository.latest_changesets(
460 "latin-1-dir/test-#{@char_1}-2.txt", '64f1f3e89', 1)
455 "latin-1-dir/test-#{CHAR_1_HEX}-2.txt", '64f1f3e89', 1)
461 assert_equal [
456 assert_equal [
462 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
457 '64f1f3e89ad1cb57976ff0ad99a107012ba3481d',
463 ], changesets.collect(&:revision)
458 ], changesets.collect(&:revision)
@@ -475,7 +470,7 class RepositoryGitTest < ActiveSupport::TestCase
475 @project.reload
470 @project.reload
476 assert_equal NUM_REV, @repository.changesets.count
471 assert_equal NUM_REV, @repository.changesets.count
477 changesets = @repository.latest_changesets(
472 changesets = @repository.latest_changesets(
478 "latin-1-dir/test-#{@char_1}-subdir", '1ca7f5ed')
473 "latin-1-dir/test-#{CHAR_1_HEX}-subdir", '1ca7f5ed')
479 assert_equal [
474 assert_equal [
480 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
475 '1ca7f5ed374f3cb31a93ae5215c2e25cc6ec5127',
481 ], changesets.collect(&:revision)
476 ], changesets.collect(&:revision)
@@ -538,13 +533,9 class RepositoryGitTest < ActiveSupport::TestCase
538 @repository.fetch_changesets
533 @repository.fetch_changesets
539 @project.reload
534 @project.reload
540 assert_equal NUM_REV, @repository.changesets.count
535 assert_equal NUM_REV, @repository.changesets.count
541 str_felix_hex = FELIX_HEX.dup
542 if str_felix_hex.respond_to?(:force_encoding)
543 str_felix_hex.force_encoding('UTF-8')
544 end
545 c = @repository.changesets.find_by_revision(
536 c = @repository.changesets.find_by_revision(
546 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
537 'ed5bb786bbda2dee66a2d50faf51429dbc043a7b')
547 assert_equal "#{str_felix_hex} <felix@fachschaften.org>", c.committer
538 assert_equal "#{FELIX_HEX} <felix@fachschaften.org>", c.committer
548 end
539 end
549
540
550 def test_previous
541 def test_previous
@@ -24,7 +24,9 class RepositoryMercurialTest < ActiveSupport::TestCase
24
24
25 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
25 REPOSITORY_PATH = Rails.root.join('tmp/test/mercurial_repository').to_s
26 NUM_REV = 34
26 NUM_REV = 34
27 CHAR_1_HEX = "\xc3\x9c"
27
28 CHAR_1_HEX = "\xc3\x9c".force_encoding('UTF-8')
29 BRANCH_CHAR_1 = "branch-#{CHAR_1_HEX}-01".force_encoding('UTF-8')
28
30
29 def setup
31 def setup
30 @project = Project.find(3)
32 @project = Project.find(3)
@@ -34,16 +36,6 class RepositoryMercurialTest < ActiveSupport::TestCase
34 :path_encoding => 'ISO-8859-1'
36 :path_encoding => 'ISO-8859-1'
35 )
37 )
36 assert @repository
38 assert @repository
37 @char_1 = CHAR_1_HEX.dup
38 @tag_char_1 = "tag-#{CHAR_1_HEX}-00"
39 @branch_char_0 = "branch-#{CHAR_1_HEX}-00"
40 @branch_char_1 = "branch-#{CHAR_1_HEX}-01"
41 if @char_1.respond_to?(:force_encoding)
42 @char_1.force_encoding('UTF-8')
43 @tag_char_1.force_encoding('UTF-8')
44 @branch_char_0.force_encoding('UTF-8')
45 @branch_char_1.force_encoding('UTF-8')
46 end
47 end
39 end
48
40
49 def test_blank_path_to_repository_error_message
41 def test_blank_path_to_repository_error_message
@@ -59,8 +51,7 class RepositoryMercurialTest < ActiveSupport::TestCase
59
51
60 def test_blank_path_to_repository_error_message_fr
52 def test_blank_path_to_repository_error_message_fr
61 set_language_if_valid 'fr'
53 set_language_if_valid 'fr'
62 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)"
54 str = "Chemin du d\xc3\xa9p\xc3\xb4t doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
63 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
64 repo = Repository::Mercurial.new(
55 repo = Repository::Mercurial.new(
65 :project => @project,
56 :project => @project,
66 :url => "",
57 :url => "",
@@ -362,11 +353,11 class RepositoryMercurialTest < ActiveSupport::TestCase
362 assert_equal NUM_REV, @repository.changesets.count
353 assert_equal NUM_REV, @repository.changesets.count
363
354
364 if @repository.scm.class.client_version_above?([1, 6])
355 if @repository.scm.class.client_version_above?([1, 6])
365 changesets = @repository.latest_changesets('', @branch_char_1)
356 changesets = @repository.latest_changesets('', BRANCH_CHAR_1)
366 assert_equal %w|27 26|, changesets.collect(&:revision)
357 assert_equal %w|27 26|, changesets.collect(&:revision)
367 end
358 end
368
359
369 changesets = @repository.latest_changesets("latin-1-dir/test-#{@char_1}-subdir", @branch_char_1)
360 changesets = @repository.latest_changesets("latin-1-dir/test-#{CHAR_1_HEX}-subdir", BRANCH_CHAR_1)
370 assert_equal %w|27|, changesets.collect(&:revision)
361 assert_equal %w|27|, changesets.collect(&:revision)
371 end
362 end
372
363
@@ -429,8 +420,8 class RepositoryMercurialTest < ActiveSupport::TestCase
429 scmid3 = scmid_for_assert(hex3, is_short_scmid)
420 scmid3 = scmid_for_assert(hex3, is_short_scmid)
430 assert_equal 1, c3.size
421 assert_equal 1, c3.size
431 assert_equal 'A', c3[0].action
422 assert_equal 'A', c3[0].action
432 assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path
423 assert_equal "/latin-1-dir/test-#{CHAR_1_HEX}-1.txt", c3[0].path
433 assert_equal "/latin-1-dir/test-#{@char_1}.txt", c3[0].from_path
424 assert_equal "/latin-1-dir/test-#{CHAR_1_HEX}.txt", c3[0].from_path
434 assert_equal scmid3, c3[0].from_revision
425 assert_equal scmid3, c3[0].from_revision
435 end
426 end
436 private :assert_copied_files
427 private :assert_copied_files
@@ -202,13 +202,7 class RepositorySubversionTest < ActiveSupport::TestCase
202
202
203 def test_log_encoding_ignore_setting
203 def test_log_encoding_ignore_setting
204 with_settings :commit_logs_encoding => 'windows-1252' do
204 with_settings :commit_logs_encoding => 'windows-1252' do
205 s1 = "\xC2\x80"
205 s2 = "\xc3\x82\xc2\x80".force_encoding('UTF-8')
206 s2 = "\xc3\x82\xc2\x80"
207 if s1.respond_to?(:force_encoding)
208 s1.force_encoding('ISO-8859-1')
209 s2.force_encoding('UTF-8')
210 assert_equal s1.encode('UTF-8'), s2
211 end
212 c = Changeset.new(:repository => @repository,
206 c = Changeset.new(:repository => @repository,
213 :comments => s2,
207 :comments => s2,
214 :revision => '123',
208 :revision => '123',
@@ -54,8 +54,7 class RepositoryTest < ActiveSupport::TestCase
54
54
55 def test_blank_log_encoding_error_message_fr
55 def test_blank_log_encoding_error_message_fr
56 set_language_if_valid 'fr'
56 set_language_if_valid 'fr'
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)"
57 str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)".force_encoding('UTF-8')
58 str.force_encoding('UTF-8') if str.respond_to?(:force_encoding)
59 repo = Repository::Bazaar.new(
58 repo = Repository::Bazaar.new(
60 :project => Project.find(3),
59 :project => Project.find(3),
61 :url => "/test"
60 :url => "/test"
@@ -175,7 +174,7 class RepositoryTest < ActiveSupport::TestCase
175
174
176 def test_destroy_should_delete_parents_associations
175 def test_destroy_should_delete_parents_associations
177 changeset = Changeset.find(102)
176 changeset = Changeset.find(102)
178 changeset.parents = Changeset.where(:id => [100, 101]).all
177 changeset.parents = Changeset.where(:id => [100, 101]).to_a
179 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
178 assert_difference 'Changeset.connection.select_all("select * from changeset_parents").count', -2 do
180 Repository.find(10).destroy
179 Repository.find(10).destroy
181 end
180 end
@@ -183,7 +182,7 class RepositoryTest < ActiveSupport::TestCase
183
182
184 def test_destroy_should_delete_issues_associations
183 def test_destroy_should_delete_issues_associations
185 changeset = Changeset.find(102)
184 changeset = Changeset.find(102)
186 changeset.issues = Issue.where(:id => [1, 2]).all
185 changeset.issues = Issue.where(:id => [1, 2]).to_a
187 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
186 assert_difference 'Changeset.connection.select_all("select * from changesets_issues").count', -2 do
188 Repository.find(10).destroy
187 Repository.find(10).destroy
189 end
188 end
@@ -21,16 +21,16 class RoleTest < ActiveSupport::TestCase
21 fixtures :roles, :workflows, :trackers
21 fixtures :roles, :workflows, :trackers
22
22
23 def test_sorted_scope
23 def test_sorted_scope
24 assert_equal Role.all.sort, Role.sorted.all
24 assert_equal Role.all.sort, Role.sorted.to_a
25 end
25 end
26
26
27 def test_givable_scope
27 def test_givable_scope
28 assert_equal Role.all.reject(&:builtin?).sort, Role.givable.all
28 assert_equal Role.all.reject(&:builtin?).sort, Role.givable.to_a
29 end
29 end
30
30
31 def test_builtin_scope
31 def test_builtin_scope
32 assert_equal Role.all.select(&:builtin?).sort, Role.builtin(true).all.sort
32 assert_equal Role.all.select(&:builtin?).sort, Role.builtin(true).to_a.sort
33 assert_equal Role.all.reject(&:builtin?).sort, Role.builtin(false).all.sort
33 assert_equal Role.all.reject(&:builtin?).sort, Role.builtin(false).to_a.sort
34 end
34 end
35
35
36 def test_copy_from
36 def test_copy_from
@@ -21,7 +21,7 class TrackerTest < ActiveSupport::TestCase
21 fixtures :trackers, :workflows, :issue_statuses, :roles, :issues
21 fixtures :trackers, :workflows, :issue_statuses, :roles, :issues
22
22
23 def test_sorted_scope
23 def test_sorted_scope
24 assert_equal Tracker.all.sort, Tracker.sorted.all
24 assert_equal Tracker.all.sort, Tracker.sorted.to_a
25 end
25 end
26
26
27 def test_named_scope
27 def test_named_scope
@@ -27,6 +27,8 class UserTest < ActiveSupport::TestCase
27 :groups_users,
27 :groups_users,
28 :enabled_modules
28 :enabled_modules
29
29
30 include Redmine::I18n
31
30 def setup
32 def setup
31 @admin = User.find(1)
33 @admin = User.find(1)
32 @jsmith = User.find(2)
34 @jsmith = User.find(2)
@@ -34,8 +36,9 class UserTest < ActiveSupport::TestCase
34 end
36 end
35
37
36 def test_sorted_scope_should_sort_user_by_display_name
38 def test_sorted_scope_should_sort_user_by_display_name
37 assert_equal User.all.map(&:name).map(&:downcase).sort,
39 # Use .active to ignore anonymous with localized display name
38 User.sorted.map(&:name).map(&:downcase)
40 assert_equal User.active.map(&:name).map(&:downcase).sort,
41 User.active.sorted.map(&:name).map(&:downcase)
39 end
42 end
40
43
41 def test_generate
44 def test_generate
@@ -853,29 +856,61 class UserTest < ActiveSupport::TestCase
853 end
856 end
854
857
855 def test_roles_for_project_with_non_member_with_public_project_should_return_non_member
858 def test_roles_for_project_with_non_member_with_public_project_should_return_non_member
859 set_language_if_valid 'en'
856 roles = User.find(8).roles_for_project(Project.find(1))
860 roles = User.find(8).roles_for_project(Project.find(1))
857 assert_equal ["Non member"], roles.map(&:name)
861 assert_equal ["Non member"], roles.map(&:name)
858 end
862 end
859
863
860 def test_roles_for_project_with_non_member_with_public_project_should_return_no_roles
864 def test_roles_for_project_with_non_member_with_public_project_and_override_should_return_override_roles
865 project = Project.find(1)
866 Member.create!(:project => project, :principal => Group.non_member, :role_ids => [1, 2])
867 roles = User.find(8).roles_for_project(project)
868 assert_equal ["Developer", "Manager"], roles.map(&:name).sort
869 end
870
871 def test_roles_for_project_with_non_member_with_private_project_should_return_no_roles
861 Project.find(1).update_attribute :is_public, false
872 Project.find(1).update_attribute :is_public, false
862
873
863 roles = User.find(8).roles_for_project(Project.find(1))
874 roles = User.find(8).roles_for_project(Project.find(1))
864 assert_equal [], roles.map(&:name)
875 assert_equal [], roles.map(&:name)
865 end
876 end
866
877
878 def test_roles_for_project_with_non_member_with_private_project_and_override_should_return_no_roles
879 project = Project.find(1)
880 project.update_attribute :is_public, false
881 Member.create!(:project => project, :principal => Group.non_member, :role_ids => [1, 2])
882 roles = User.find(8).roles_for_project(project)
883 assert_equal [], roles.map(&:name).sort
884 end
885
867 def test_roles_for_project_with_anonymous_with_public_project_should_return_anonymous
886 def test_roles_for_project_with_anonymous_with_public_project_should_return_anonymous
887 set_language_if_valid 'en'
868 roles = User.anonymous.roles_for_project(Project.find(1))
888 roles = User.anonymous.roles_for_project(Project.find(1))
869 assert_equal ["Anonymous"], roles.map(&:name)
889 assert_equal ["Anonymous"], roles.map(&:name)
870 end
890 end
871
891
872 def test_roles_for_project_with_anonymous_with_public_project_should_return_no_roles
892 def test_roles_for_project_with_anonymous_with_public_project_and_override_should_return_override_roles
893 project = Project.find(1)
894 Member.create!(:project => project, :principal => Group.anonymous, :role_ids => [1, 2])
895 roles = User.anonymous.roles_for_project(project)
896 assert_equal ["Developer", "Manager"], roles.map(&:name).sort
897 end
898
899 def test_roles_for_project_with_anonymous_with_private_project_should_return_no_roles
873 Project.find(1).update_attribute :is_public, false
900 Project.find(1).update_attribute :is_public, false
874
901
875 roles = User.anonymous.roles_for_project(Project.find(1))
902 roles = User.anonymous.roles_for_project(Project.find(1))
876 assert_equal [], roles.map(&:name)
903 assert_equal [], roles.map(&:name)
877 end
904 end
878
905
906 def test_roles_for_project_with_anonymous_with_private_project_and_override_should_return_no_roles
907 project = Project.find(1)
908 project.update_attribute :is_public, false
909 Member.create!(:project => project, :principal => Group.anonymous, :role_ids => [1, 2])
910 roles = User.anonymous.roles_for_project(project)
911 assert_equal [], roles.map(&:name).sort
912 end
913
879 def test_projects_by_role_for_user_with_role
914 def test_projects_by_role_for_user_with_role
880 user = User.find(2)
915 user = User.find(2)
881 assert_kind_of Hash, user.projects_by_role
916 assert_kind_of Hash, user.projects_by_role
@@ -1059,10 +1094,10 class UserTest < ActiveSupport::TestCase
1059 end
1094 end
1060
1095
1061 should "return true only if user has permission on all these projects" do
1096 should "return true only if user has permission on all these projects" do
1062 assert_equal true, @admin.allowed_to?(:view_project, Project.all)
1097 assert_equal true, @admin.allowed_to?(:view_project, Project.all.to_a)
1063 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all) #cannot see Project(2)
1098 assert_equal false, @dlopper.allowed_to?(:view_project, Project.all.to_a) #cannot see Project(2)
1064 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects) #Manager or Developer everywhere
1099 assert_equal true, @jsmith.allowed_to?(:edit_issues, @jsmith.projects.to_a) #Manager or Developer everywhere
1065 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects) #Dev cannot delete_issue_watchers
1100 assert_equal false, @jsmith.allowed_to?(:delete_issue_watchers, @jsmith.projects.to_a) #Dev cannot delete_issue_watchers
1066 end
1101 end
1067
1102
1068 should "behave correctly with arrays of 1 project" do
1103 should "behave correctly with arrays of 1 project" do
@@ -124,7 +124,7 class VersionTest < ActiveSupport::TestCase
124 v5 = Version.create!(:project_id => 1, :name => 'v5', :effective_date => '2012-07-02')
124 v5 = Version.create!(:project_id => 1, :name => 'v5', :effective_date => '2012-07-02')
125
125
126 assert_equal [v5, v3, v1, v2, v4], [v1, v2, v3, v4, v5].sort
126 assert_equal [v5, v3, v1, v2, v4], [v1, v2, v3, v4, v5].sort
127 assert_equal [v5, v3, v1, v2, v4], Version.sorted.all
127 assert_equal [v5, v3, v1, v2, v4], Version.sorted.to_a
128 end
128 end
129
129
130 def test_completed_should_be_false_when_due_today
130 def test_completed_should_be_false_when_due_today
@@ -78,8 +78,7 class WikiTest < ActiveSupport::TestCase
78 end
78 end
79
79
80 def test_titleize
80 def test_titleize
81 ja_test = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88"
81 ja_test = "\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding('UTF-8')
82 ja_test.force_encoding('UTF-8') if ja_test.respond_to?(:force_encoding)
83 assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES')
82 assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES')
84 assert_equal ja_test, Wiki.titleize(ja_test)
83 assert_equal ja_test, Wiki.titleize(ja_test)
85 end
84 end
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
This diff has been collapsed as it changes many lines, (1098 lines changed) Show them Hide them
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now