mirror of
https://github.com/redmine/redmine.git
synced 2026-07-06 01:47:55 +02:00
Merged rails-4.1 branch (#14534).
git-svn-id: http://svn.redmine.org/redmine/trunk@13482 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
3
.travis.run-test.sh
Normal file
3
.travis.run-test.sh
Normal file
@@ -0,0 +1,3 @@
|
||||
#! /bin/sh
|
||||
|
||||
JRUBY_OPTS=-J-Xmx1024m bundle exec rake test:${TEST_SUITE}
|
||||
@@ -3,8 +3,6 @@
|
||||
# You can also run tests on your environment.
|
||||
language: ruby
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- 1.9.3
|
||||
- 2.0
|
||||
- 2.1
|
||||
@@ -34,6 +32,7 @@ script:
|
||||
- "bundle install"
|
||||
- "RUN_ON_NOT_OFFICIAL='' RUBY_VER=1.9 BRANCH=trunk bundle exec rake config/database.yml"
|
||||
- "bundle install"
|
||||
- "JRUBY_OPTS=-J-Xmx1024m bundle exec rake ci"
|
||||
- "bundle exec rake ci:setup"
|
||||
- "sh .travis.run-test.sh"
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
34
Gemfile
34
Gemfile
@@ -1,12 +1,17 @@
|
||||
source 'https://rubygems.org'
|
||||
|
||||
gem "rails", "3.2.19"
|
||||
gem "rails", "4.1.6"
|
||||
gem "jquery-rails", "~> 3.1.1"
|
||||
gem "coderay", "~> 1.1.0"
|
||||
gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby]
|
||||
gem "builder", ">= 3.0.4"
|
||||
gem "request_store", "1.0.5"
|
||||
gem "mime-types"
|
||||
gem "awesome_nested_set", "3.0.0"
|
||||
gem "protected_attributes"
|
||||
gem "actionpack-action_caching"
|
||||
|
||||
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
|
||||
gem 'tzinfo-data', platforms: [:mingw, :mswin, :jruby]
|
||||
gem "rbpdf", "~> 1.18.1"
|
||||
|
||||
# Optional gem for LDAP authentication
|
||||
@@ -23,16 +28,12 @@ end
|
||||
platforms :mri, :mingw do
|
||||
# Optional gem for exporting the gantt to a PNG file, not supported with jruby
|
||||
group :rmagick do
|
||||
# RMagick 2 supports ruby 1.9
|
||||
# RMagick 1 would be fine for ruby 1.8 but Bundler does not support
|
||||
# different requirements for the same gem on different platforms
|
||||
gem "rmagick", ">= 2.0.0"
|
||||
end
|
||||
|
||||
# Optional Markdown support, not for JRuby
|
||||
group :markdown do
|
||||
# TODO: upgrade to redcarpet 3.x when ruby1.8 support is dropped
|
||||
gem "redcarpet", "~> 2.3.0"
|
||||
gem "redcarpet", "~> 3.1.2"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -57,7 +58,6 @@ if File.exist?(database_file)
|
||||
gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
|
||||
when 'mysql'
|
||||
gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw]
|
||||
gem "activerecord-jdbcmysql-adapter", :platforms => :jruby
|
||||
when /postgresql/
|
||||
gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw]
|
||||
@@ -85,24 +85,20 @@ group :development do
|
||||
end
|
||||
|
||||
group :test do
|
||||
gem "shoulda", "~> 3.3.2"
|
||||
gem "shoulda-matchers", "1.4.1"
|
||||
gem "minitest"
|
||||
gem "shoulda-context"
|
||||
gem "mocha", "~> 1.0.0", :require => 'mocha/api'
|
||||
if RUBY_VERSION >= '1.9.3'
|
||||
gem "capybara", "~> 2.1.0"
|
||||
gem "selenium-webdriver"
|
||||
end
|
||||
# For running UI tests
|
||||
gem "capybara", "~> 2.1.0"
|
||||
gem "selenium-webdriver"
|
||||
end
|
||||
|
||||
local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local")
|
||||
if File.exists?(local_gemfile)
|
||||
puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v`
|
||||
instance_eval File.read(local_gemfile)
|
||||
eval_gemfile local_gemfile
|
||||
end
|
||||
|
||||
# Load plugins' Gemfiles
|
||||
Dir.glob File.expand_path("../plugins/*/{Gemfile,PluginGemfile}", __FILE__) do |file|
|
||||
puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v`
|
||||
#TODO: switch to "eval_gemfile file" when bundler >= 1.2.0 will be required (rails 4)
|
||||
instance_eval File.read(file), file
|
||||
eval_gemfile file
|
||||
end
|
||||
|
||||
@@ -34,7 +34,7 @@ class AdminController < ApplicationController
|
||||
|
||||
scope = Project.status(@status).order('lft')
|
||||
scope = scope.like(params[:name]) if params[:name].present?
|
||||
@projects = scope.all
|
||||
@projects = scope.to_a
|
||||
|
||||
render :action => "projects", :layout => false if request.xhr?
|
||||
end
|
||||
|
||||
@@ -496,7 +496,7 @@ class ApplicationController < ActionController::Base
|
||||
end
|
||||
|
||||
def render_feed(items, options={})
|
||||
@items = items || []
|
||||
@items = (items || []).to_a
|
||||
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
|
||||
@items = @items.slice(0, Setting.feeds_limit.to_i)
|
||||
@title = options[:title] || Setting.app_title
|
||||
|
||||
@@ -26,7 +26,7 @@ class AutoCompletesController < ApplicationController
|
||||
if q.match(/\A#?(\d+)\z/)
|
||||
@issues << scope.find_by_id($1.to_i)
|
||||
end
|
||||
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all
|
||||
@issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).to_a
|
||||
@issues.compact!
|
||||
end
|
||||
render :layout => false
|
||||
|
||||
@@ -25,7 +25,7 @@ class BoardsController < ApplicationController
|
||||
helper :watchers
|
||||
|
||||
def index
|
||||
@boards = @project.boards.includes(:project, :last_message => :author).all
|
||||
@boards = @project.boards.preload(:project, :last_message => :author).to_a
|
||||
# show the board if there is only one
|
||||
if @boards.size == 1
|
||||
@board = @boards.first
|
||||
@@ -45,12 +45,13 @@ class BoardsController < ApplicationController
|
||||
@topic_pages = Paginator.new @topic_count, per_page_option, params['page']
|
||||
@topics = @board.topics.
|
||||
reorder("#{Message.table_name}.sticky DESC").
|
||||
includes(:last_reply).
|
||||
joins("LEFT OUTER JOIN #{Message.table_name} last_replies_messages ON last_replies_messages.id = #{Message.table_name}.last_reply_id").
|
||||
references(:last_reply).
|
||||
limit(@topic_pages.per_page).
|
||||
offset(@topic_pages.offset).
|
||||
order(sort_clause).
|
||||
preload(:author, {:last_reply => :author}).
|
||||
all
|
||||
to_a
|
||||
@message = Message.new(:board => @board)
|
||||
render :action => 'show', :layout => !request.xhr?
|
||||
}
|
||||
@@ -59,7 +60,7 @@ class BoardsController < ApplicationController
|
||||
reorder('created_on DESC').
|
||||
includes(:author, :board).
|
||||
limit(Setting.feeds_limit.to_i).
|
||||
all
|
||||
to_a
|
||||
render_feed(@messages, :title => "#{@project}: #{@board}")
|
||||
}
|
||||
end
|
||||
|
||||
@@ -27,7 +27,7 @@ class DocumentsController < ApplicationController
|
||||
|
||||
def index
|
||||
@sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category'
|
||||
documents = @project.documents.includes(:attachments, :category).all
|
||||
documents = @project.documents.includes(:attachments, :category).to_a
|
||||
case @sort_by
|
||||
when 'date'
|
||||
@grouped = documents.group_by {|d| d.updated_on.to_date }
|
||||
@@ -43,7 +43,7 @@ class DocumentsController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
@attachments = @document.attachments.all
|
||||
@attachments = @document.attachments.to_a
|
||||
end
|
||||
|
||||
def new
|
||||
@@ -69,7 +69,7 @@ class DocumentsController < ApplicationController
|
||||
|
||||
def update
|
||||
@document.safe_attributes = params[:document]
|
||||
if request.put? and @document.save
|
||||
if @document.save
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to document_path(@document)
|
||||
else
|
||||
|
||||
@@ -32,7 +32,7 @@ class EnumerationsController < ApplicationController
|
||||
format.api {
|
||||
@klass = Enumeration.get_subclass(params[:type])
|
||||
if @klass
|
||||
@enumerations = @klass.shared.sorted.all
|
||||
@enumerations = @klass.shared.sorted.to_a
|
||||
else
|
||||
render_404
|
||||
end
|
||||
@@ -56,7 +56,7 @@ class EnumerationsController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
if request.put? && @enumeration.update_attributes(params[:enumeration])
|
||||
if @enumeration.update_attributes(params[:enumeration])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to enumerations_path
|
||||
else
|
||||
@@ -75,7 +75,7 @@ class EnumerationsController < ApplicationController
|
||||
redirect_to enumerations_path
|
||||
return
|
||||
end
|
||||
@enumerations = @enumeration.class.system.all - [@enumeration]
|
||||
@enumerations = @enumeration.class.system.to_a - [@enumeration]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -31,8 +31,10 @@ class FilesController < ApplicationController
|
||||
'size' => "#{Attachment.table_name}.filesize",
|
||||
'downloads' => "#{Attachment.table_name}.downloads"
|
||||
|
||||
@containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)]
|
||||
@containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse
|
||||
@containers = [Project.includes(:attachments).
|
||||
references(:attachments).reorder(sort_clause).find(@project.id)]
|
||||
@containers += @project.versions.includes(:attachments).
|
||||
references(:attachments).reorder(sort_clause).to_a.sort.reverse
|
||||
render :layout => !request.xhr?
|
||||
end
|
||||
|
||||
|
||||
@@ -27,13 +27,13 @@ class GroupsController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@groups = Group.sorted.all
|
||||
@groups = Group.sorted.to_a
|
||||
@user_count_by_group_id = user_count_by_group_id
|
||||
}
|
||||
format.api {
|
||||
scope = Group.sorted
|
||||
scope = scope.givable unless params[:builtin] == '1'
|
||||
@groups = scope.all
|
||||
@groups = scope.to_a
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -95,7 +95,7 @@ class GroupsController < ApplicationController
|
||||
end
|
||||
|
||||
def add_users
|
||||
@users = User.where(:id => (params[:user_id] || params[:user_ids])).all
|
||||
@users = User.where(:id => (params[:user_id] || params[:user_ids])).to_a
|
||||
@group.users << @users if request.post?
|
||||
respond_to do |format|
|
||||
format.html { redirect_to edit_group_path(@group, :tab => 'users') }
|
||||
|
||||
@@ -27,7 +27,7 @@ class IssueCategoriesController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.api { @categories = @project.issue_categories.all }
|
||||
format.api { @categories = @project.issue_categories.to_a }
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class IssueStatusesController < ApplicationController
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@issue_statuses = IssueStatus.order('position').all
|
||||
@issue_statuses = IssueStatus.order('position').to_a
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -104,15 +104,16 @@ class IssuesController < ApplicationController
|
||||
end
|
||||
|
||||
def show
|
||||
@journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all
|
||||
@journals = @issue.journals.includes(:user, :details).
|
||||
references(:user, :details).
|
||||
reorder("#{Journal.table_name}.id ASC").to_a
|
||||
@journals.each_with_index {|j,i| j.indice = i+1}
|
||||
@journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
|
||||
Journal.preload_journals_details_custom_fields(@journals)
|
||||
# TODO: use #select! when ruby1.8 support is dropped
|
||||
@journals.reject! {|journal| !journal.notes? && journal.visible_details.empty?}
|
||||
@journals.select! {|journal| journal.notes? || journal.visible_details.any?}
|
||||
@journals.reverse! if User.current.wants_comments_in_reverse_order?
|
||||
|
||||
@changesets = @issue.changesets.visible.all
|
||||
@changesets = @issue.changesets.visible.to_a
|
||||
@changesets.reverse! if User.current.wants_comments_in_reverse_order?
|
||||
|
||||
@relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? }
|
||||
@@ -189,7 +190,7 @@ class IssuesController < ApplicationController
|
||||
rescue ActiveRecord::StaleObjectError
|
||||
@conflict = true
|
||||
if params[:last_journal_id]
|
||||
@conflict_journals = @issue.journals_after(params[:last_journal_id]).all
|
||||
@conflict_journals = @issue.journals_after(params[:last_journal_id]).to_a
|
||||
@conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project)
|
||||
end
|
||||
end
|
||||
@@ -301,7 +302,7 @@ class IssuesController < ApplicationController
|
||||
else
|
||||
@saved_issues = @issues
|
||||
@unsaved_issues = unsaved_issues
|
||||
@issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).all
|
||||
@issues = Issue.visible.where(:id => @unsaved_issues.map(&:id)).to_a
|
||||
bulk_edit
|
||||
render :action => 'bulk_edit'
|
||||
end
|
||||
@@ -375,7 +376,9 @@ class IssuesController < ApplicationController
|
||||
def update_issue_from_params
|
||||
@edit_allowed = User.current.allowed_to?(:edit_issues, @project)
|
||||
@time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project)
|
||||
@time_entry.attributes = params[:time_entry]
|
||||
if params[:time_entry]
|
||||
@time_entry.attributes = params[:time_entry]
|
||||
end
|
||||
|
||||
@issue.init_journal(User.current)
|
||||
|
||||
@@ -422,7 +425,9 @@ class IssuesController < ApplicationController
|
||||
@issue.project = @project
|
||||
@issue.author ||= User.current
|
||||
# Tracker must be set before custom field values
|
||||
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
||||
tracker_id = (params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id]
|
||||
tracker = tracker_id.present? ? @project.trackers.find(tracker_id) : @project.trackers.first
|
||||
@issue.tracker ||= tracker
|
||||
if @issue.tracker.nil?
|
||||
render_error l(:error_no_tracker_in_project)
|
||||
return false
|
||||
|
||||
@@ -34,7 +34,6 @@ class JournalsController < ApplicationController
|
||||
retrieve_query
|
||||
sort_init 'id', 'desc'
|
||||
sort_update(@query.sortable_columns)
|
||||
|
||||
if @query.valid?
|
||||
@journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC",
|
||||
:limit => 25)
|
||||
|
||||
@@ -32,7 +32,7 @@ class MembersController < ApplicationController
|
||||
order("#{Member.table_name}.id").
|
||||
limit(@limit).
|
||||
offset(@offset).
|
||||
all
|
||||
to_a
|
||||
respond_to do |format|
|
||||
format.html { head 406 }
|
||||
format.api
|
||||
@@ -63,7 +63,10 @@ class MembersController < ApplicationController
|
||||
|
||||
respond_to do |format|
|
||||
format.html { redirect_to_settings_in_projects }
|
||||
format.js { @members = members }
|
||||
format.js {
|
||||
@members = members
|
||||
@member = Member.new
|
||||
}
|
||||
format.api {
|
||||
@member = members.first
|
||||
if @member.valid?
|
||||
|
||||
@@ -43,10 +43,10 @@ class MessagesController < ApplicationController
|
||||
@reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page
|
||||
@replies = @topic.children.
|
||||
includes(:author, :attachments, {:board => :project}).
|
||||
reorder("#{Message.table_name}.created_on ASC").
|
||||
reorder("#{Message.table_name}.created_on ASC, #{Message.table_name}.id ASC").
|
||||
limit(@reply_pages.per_page).
|
||||
offset(@reply_pages.offset).
|
||||
all
|
||||
to_a
|
||||
|
||||
@reply = Message.new(:subject => "RE: #{@message.subject}")
|
||||
render :action => "show", :layout => false if request.xhr?
|
||||
|
||||
@@ -53,8 +53,8 @@ class MyController < ApplicationController
|
||||
@user = User.current
|
||||
@pref = @user.pref
|
||||
if request.post?
|
||||
@user.safe_attributes = params[:user]
|
||||
@user.pref.attributes = params[:pref]
|
||||
@user.safe_attributes = params[:user] if params[:user]
|
||||
@user.pref.attributes = params[:pref] if params[:pref]
|
||||
if @user.save
|
||||
@user.pref.save
|
||||
set_language_if_valid @user.language
|
||||
|
||||
@@ -46,7 +46,7 @@ class NewsController < ApplicationController
|
||||
order("#{News.table_name}.created_on DESC").
|
||||
limit(@limit).
|
||||
offset(@offset).
|
||||
all
|
||||
to_a
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@news = News.new # for adding news inline
|
||||
|
||||
@@ -20,7 +20,7 @@ class ProjectEnumerationsController < ApplicationController
|
||||
before_filter :authorize
|
||||
|
||||
def update
|
||||
if request.put? && params[:enumerations]
|
||||
if params[:enumerations]
|
||||
Project.transaction do
|
||||
params[:enumerations].each do |id, activity|
|
||||
@project.update_or_create_time_entry_activity(id, activity)
|
||||
|
||||
@@ -53,30 +53,30 @@ class ProjectsController < ApplicationController
|
||||
unless params[:closed]
|
||||
scope = scope.active
|
||||
end
|
||||
@projects = scope.visible.order('lft').all
|
||||
@projects = scope.visible.order('lft').to_a
|
||||
}
|
||||
format.api {
|
||||
@offset, @limit = api_offset_and_limit
|
||||
@project_count = Project.visible.count
|
||||
@projects = Project.visible.offset(@offset).limit(@limit).order('lft').all
|
||||
@projects = Project.visible.offset(@offset).limit(@limit).order('lft').to_a
|
||||
}
|
||||
format.atom {
|
||||
projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all
|
||||
projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).to_a
|
||||
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@trackers = Tracker.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.sorted.to_a
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@project = Project.new
|
||||
@project.safe_attributes = params[:project]
|
||||
end
|
||||
|
||||
def create
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@trackers = Tracker.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.sorted.to_a
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@project = Project.new
|
||||
@project.safe_attributes = params[:project]
|
||||
|
||||
@@ -109,8 +109,8 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
|
||||
def copy
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@trackers = Tracker.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.sorted.to_a
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@source_project = Project.find(params[:id])
|
||||
if request.get?
|
||||
@project = Project.copy_from(@source_project)
|
||||
@@ -145,8 +145,8 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
|
||||
@users_by_role = @project.users_by_role
|
||||
@subprojects = @project.children.visible.all
|
||||
@news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all
|
||||
@subprojects = @project.children.visible.to_a
|
||||
@news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").to_a
|
||||
@trackers = @project.rolled_up_trackers
|
||||
|
||||
cond = @project.project_condition(Setting.display_subprojects_issues?)
|
||||
@@ -167,10 +167,10 @@ class ProjectsController < ApplicationController
|
||||
end
|
||||
|
||||
def settings
|
||||
@issue_custom_fields = IssueCustomField.sorted.all
|
||||
@issue_custom_fields = IssueCustomField.sorted.to_a
|
||||
@issue_category ||= IssueCategory.new
|
||||
@member ||= @project.members.new
|
||||
@trackers = Tracker.sorted.all
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@wiki ||= @project.wiki
|
||||
end
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@ class QueriesController < ApplicationController
|
||||
order("#{Query.table_name}.name").
|
||||
limit(@limit).
|
||||
offset(@offset).
|
||||
all
|
||||
to_a
|
||||
respond_to do |format|
|
||||
format.html {render_error :status => 406}
|
||||
format.api
|
||||
end
|
||||
end
|
||||
|
||||
@@ -90,6 +90,6 @@ class ReportsController < ApplicationController
|
||||
private
|
||||
|
||||
def find_issue_statuses
|
||||
@statuses = IssueStatus.sorted.all
|
||||
@statuses = IssueStatus.sorted.to_a
|
||||
end
|
||||
end
|
||||
|
||||
@@ -69,7 +69,7 @@ class RepositoriesController < ApplicationController
|
||||
@repository.merge_extra_info(attrs[:attrs_extra])
|
||||
end
|
||||
@repository.project = @project
|
||||
if request.put? && @repository.save
|
||||
if @repository.save
|
||||
redirect_to settings_project_path(@project, :tab => 'repositories')
|
||||
else
|
||||
render :action => 'edit'
|
||||
@@ -94,7 +94,7 @@ class RepositoriesController < ApplicationController
|
||||
@committers = @repository.committers
|
||||
@users = @project.users
|
||||
additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id)
|
||||
@users += User.where(:id => additional_user_ids).all unless additional_user_ids.empty?
|
||||
@users += User.where(:id => additional_user_ids).to_a unless additional_user_ids.empty?
|
||||
@users.compact!
|
||||
@users.sort!
|
||||
if request.post? && params[:committers].is_a?(Hash)
|
||||
@@ -145,7 +145,7 @@ class RepositoriesController < ApplicationController
|
||||
limit(@changeset_pages.per_page).
|
||||
offset(@changeset_pages.offset).
|
||||
includes(:user, :repository, :parents).
|
||||
all
|
||||
to_a
|
||||
|
||||
respond_to do |format|
|
||||
format.html { render :layout => false if request.xhr? }
|
||||
|
||||
@@ -30,7 +30,7 @@ class RolesController < ApplicationController
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@roles = Role.givable.all
|
||||
@roles = Role.givable.to_a
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -47,7 +47,7 @@ class RolesController < ApplicationController
|
||||
if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy])
|
||||
@role.copy_from(@copy_from)
|
||||
end
|
||||
@roles = Role.sorted.all
|
||||
@roles = Role.sorted.to_a
|
||||
end
|
||||
|
||||
def create
|
||||
@@ -60,7 +60,7 @@ class RolesController < ApplicationController
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to roles_path
|
||||
else
|
||||
@roles = Role.sorted.all
|
||||
@roles = Role.sorted.to_a
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
@@ -69,7 +69,7 @@ class RolesController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
if request.put? and @role.update_attributes(params[:role])
|
||||
if @role.update_attributes(params[:role])
|
||||
flash[:notice] = l(:notice_successful_update)
|
||||
redirect_to roles_path
|
||||
else
|
||||
@@ -86,7 +86,7 @@ class RolesController < ApplicationController
|
||||
end
|
||||
|
||||
def permissions
|
||||
@roles = Role.sorted.all
|
||||
@roles = Role.sorted.to_a
|
||||
@permissions = Redmine::AccessControl.permissions.select { |p| !p.public? }
|
||||
if request.post?
|
||||
@roles.each do |role|
|
||||
|
||||
@@ -31,7 +31,7 @@ class SearchController < ApplicationController
|
||||
when 'my_projects'
|
||||
User.current.memberships.collect(&:project)
|
||||
when 'subprojects'
|
||||
@project ? (@project.self_and_descendants.active.all) : nil
|
||||
@project ? (@project.self_and_descendants.active.to_a) : nil
|
||||
else
|
||||
@project
|
||||
end
|
||||
|
||||
@@ -19,7 +19,8 @@ class SysController < ActionController::Base
|
||||
before_filter :check_enabled
|
||||
|
||||
def projects
|
||||
p = Project.active.has_module(:repository).order("#{Project.table_name}.identifier").preload(:repository).all
|
||||
p = Project.active.has_module(:repository).
|
||||
order("#{Project.table_name}.identifier").preload(:repository).to_a
|
||||
# extra_info attribute from repository breaks activeresource client
|
||||
render :xml => p.to_xml(
|
||||
:only => [:id, :identifier, :name, :is_public, :status],
|
||||
@@ -56,7 +57,7 @@ class SysController < ActionController::Base
|
||||
raise ActiveRecord::RecordNotFound unless project
|
||||
projects << project
|
||||
else
|
||||
projects = scope.all
|
||||
projects = scope.to_a
|
||||
end
|
||||
projects.each do |project|
|
||||
project.repositories.each do |repository|
|
||||
|
||||
@@ -52,7 +52,7 @@ class TimelogController < ApplicationController
|
||||
format.html {
|
||||
@entry_count = scope.count
|
||||
@entry_pages = Paginator.new @entry_count, per_page_option, params['page']
|
||||
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).all
|
||||
@entries = scope.offset(@entry_pages.offset).limit(@entry_pages.per_page).to_a
|
||||
@total_hours = scope.sum(:hours).to_f
|
||||
|
||||
render :layout => !request.xhr?
|
||||
@@ -60,15 +60,15 @@ class TimelogController < ApplicationController
|
||||
format.api {
|
||||
@entry_count = scope.count
|
||||
@offset, @limit = api_offset_and_limit
|
||||
@entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).all
|
||||
@entries = scope.offset(@offset).limit(@limit).preload(:custom_values => :custom_field).to_a
|
||||
}
|
||||
format.atom {
|
||||
entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").all
|
||||
entries = scope.limit(Setting.feeds_limit.to_i).reorder("#{TimeEntry.table_name}.created_on DESC").to_a
|
||||
render_feed(entries, :title => l(:label_spent_time))
|
||||
}
|
||||
format.csv {
|
||||
# Export all entries
|
||||
@entries = scope.all
|
||||
@entries = scope.to_a
|
||||
send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv')
|
||||
}
|
||||
end
|
||||
@@ -232,7 +232,7 @@ private
|
||||
end
|
||||
|
||||
def find_time_entries
|
||||
@time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).all
|
||||
@time_entries = TimeEntry.where(:id => params[:id] || params[:ids]).to_a
|
||||
raise ActiveRecord::RecordNotFound if @time_entries.empty?
|
||||
@projects = @time_entries.collect(&:project).compact.uniq
|
||||
@project = @projects.first if @projects.size == 1
|
||||
|
||||
@@ -29,14 +29,14 @@ class TrackersController < ApplicationController
|
||||
render :action => "index", :layout => false if request.xhr?
|
||||
}
|
||||
format.api {
|
||||
@trackers = Tracker.sorted.all
|
||||
@trackers = Tracker.sorted.to_a
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def new
|
||||
@tracker ||= Tracker.new(params[:tracker])
|
||||
@trackers = Tracker.sorted.all
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@projects = Project.all
|
||||
end
|
||||
|
||||
@@ -95,7 +95,7 @@ class TrackersController < ApplicationController
|
||||
redirect_to fields_trackers_path
|
||||
return
|
||||
end
|
||||
@trackers = Tracker.sorted.all
|
||||
@trackers = Tracker.sorted.to_a
|
||||
@custom_fields = IssueCustomField.all.sort
|
||||
end
|
||||
end
|
||||
|
||||
@@ -47,7 +47,7 @@ class UsersController < ApplicationController
|
||||
@user_count = scope.count
|
||||
@user_pages = Paginator.new @user_count, @limit, params['page']
|
||||
@offset ||= @user_pages.offset
|
||||
@users = scope.order(sort_clause).limit(@limit).offset(@offset).all
|
||||
@users = scope.order(sort_clause).limit(@limit).offset(@offset).to_a
|
||||
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@@ -60,7 +60,7 @@ class UsersController < ApplicationController
|
||||
|
||||
def show
|
||||
# show projects based on current user visibility
|
||||
@memberships = @user.memberships.where(Project.visible_condition(User.current)).all
|
||||
@memberships = @user.memberships.where(Project.visible_condition(User.current)).to_a
|
||||
|
||||
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
|
||||
@events_by_day = events.group_by(&:event_date)
|
||||
@@ -90,7 +90,7 @@ class UsersController < ApplicationController
|
||||
@user.admin = params[:user][:admin] || false
|
||||
@user.login = params[:user][:login]
|
||||
@user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id
|
||||
@user.pref.attributes = params[:pref]
|
||||
@user.pref.attributes = params[:pref] if params[:pref]
|
||||
|
||||
if @user.save
|
||||
Mailer.account_information(@user, @user.password).deliver if params[:send_information]
|
||||
@@ -134,7 +134,7 @@ class UsersController < ApplicationController
|
||||
# Was the account actived ? (do it before User#save clears the change)
|
||||
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
|
||||
# TODO: Similar to My#account
|
||||
@user.pref.attributes = params[:pref]
|
||||
@user.pref.attributes = params[:pref] if params[:pref]
|
||||
|
||||
if @user.save
|
||||
@user.pref.save
|
||||
|
||||
@@ -31,7 +31,7 @@ class VersionsController < ApplicationController
|
||||
def index
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
@trackers = @project.trackers.sorted.all
|
||||
@trackers = @project.trackers.sorted.to_a
|
||||
retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?})
|
||||
@with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1')
|
||||
project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id]
|
||||
@@ -56,7 +56,7 @@ class VersionsController < ApplicationController
|
||||
@versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?}
|
||||
}
|
||||
format.api {
|
||||
@versions = @project.shared_versions.all
|
||||
@versions = @project.shared_versions.to_a
|
||||
}
|
||||
end
|
||||
end
|
||||
@@ -67,7 +67,7 @@ class VersionsController < ApplicationController
|
||||
@issues = @version.fixed_issues.visible.
|
||||
includes(:status, :tracker, :priority).
|
||||
reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id").
|
||||
all
|
||||
to_a
|
||||
}
|
||||
format.api
|
||||
end
|
||||
@@ -117,7 +117,7 @@ class VersionsController < ApplicationController
|
||||
end
|
||||
|
||||
def update
|
||||
if request.put? && params[:version]
|
||||
if params[:version]
|
||||
attributes = params[:version].dup
|
||||
attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
|
||||
@version.safe_attributes = attributes
|
||||
|
||||
@@ -53,7 +53,7 @@ class WatchersController < ApplicationController
|
||||
def append
|
||||
if params[:watcher].is_a?(Hash)
|
||||
user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]]
|
||||
@users = User.active.where(:id => user_ids).all
|
||||
@users = User.active.where(:id => user_ids).to_a
|
||||
end
|
||||
if @users.blank?
|
||||
render :nothing => true
|
||||
@@ -92,7 +92,7 @@ class WatchersController < ApplicationController
|
||||
def find_watchables
|
||||
klass = Object.const_get(params[:object_type].camelcase) rescue nil
|
||||
if klass && klass.respond_to?('watched_by')
|
||||
@watchables = klass.where(:id => Array.wrap(params[:object_id])).all
|
||||
@watchables = klass.where(:id => Array.wrap(params[:object_id])).to_a
|
||||
raise Unauthorized if @watchables.any? {|w|
|
||||
if w.respond_to?(:visible?)
|
||||
!w.visible?
|
||||
|
||||
@@ -219,7 +219,7 @@ class WikiController < ApplicationController
|
||||
reorder('version DESC').
|
||||
limit(@version_pages.per_page + 1).
|
||||
offset(@version_pages.offset).
|
||||
all
|
||||
to_a
|
||||
|
||||
render :layout => false if request.xhr?
|
||||
end
|
||||
@@ -280,7 +280,7 @@ class WikiController < ApplicationController
|
||||
@pages = @wiki.pages.
|
||||
order('title').
|
||||
includes([:content, {:attachments => :author}]).
|
||||
all
|
||||
to_a
|
||||
respond_to do |format|
|
||||
format.html {
|
||||
export = render_to_string :action => 'export_multiple', :layout => false
|
||||
@@ -327,7 +327,7 @@ private
|
||||
def find_existing_or_new_page
|
||||
@page = @wiki.find_or_new_page(params[:id])
|
||||
if @wiki.page_found_with_redirect?
|
||||
redirect_to params.update(:id => @page.title)
|
||||
redirect_to_page @page
|
||||
end
|
||||
end
|
||||
|
||||
@@ -339,10 +339,14 @@ private
|
||||
return
|
||||
end
|
||||
if @wiki.page_found_with_redirect?
|
||||
redirect_to params.update(:id => @page.title)
|
||||
redirect_to_page @page
|
||||
end
|
||||
end
|
||||
|
||||
def redirect_to_page(page)
|
||||
redirect_to :action => action_name, :project_id => page.wiki.project, :id => page.title
|
||||
end
|
||||
|
||||
# Returns true if the current user is allowed to edit the page, otherwise false
|
||||
def editable?(page = @page)
|
||||
page.editable_by?(User.current)
|
||||
@@ -360,6 +364,6 @@ private
|
||||
reorder("#{WikiPage.table_name}.title").
|
||||
includes(:wiki => :project).
|
||||
includes(:parent).
|
||||
all
|
||||
to_a
|
||||
end
|
||||
end
|
||||
|
||||
@@ -86,9 +86,9 @@ class WorkflowsController < ApplicationController
|
||||
@source_role = Role.find_by_id(params[:source_role_id].to_i)
|
||||
end
|
||||
@target_trackers = params[:target_tracker_ids].blank? ?
|
||||
nil : Tracker.where(:id => params[:target_tracker_ids]).all
|
||||
nil : Tracker.where(:id => params[:target_tracker_ids]).to_a
|
||||
@target_roles = params[:target_role_ids].blank? ?
|
||||
nil : Role.where(:id => params[:target_role_ids]).all
|
||||
nil : Role.where(:id => params[:target_role_ids]).to_a
|
||||
if request.post?
|
||||
if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?)
|
||||
flash.now[:error] = l(:error_workflow_copy_source)
|
||||
@@ -113,9 +113,9 @@ class WorkflowsController < ApplicationController
|
||||
def find_roles
|
||||
ids = Array.wrap(params[:role_id])
|
||||
if ids == ['all']
|
||||
@roles = Role.sorted.all
|
||||
@roles = Role.sorted.to_a
|
||||
elsif ids.present?
|
||||
@roles = Role.where(:id => ids).all
|
||||
@roles = Role.where(:id => ids).to_a
|
||||
end
|
||||
@roles = nil if @roles.blank?
|
||||
end
|
||||
@@ -123,9 +123,9 @@ class WorkflowsController < ApplicationController
|
||||
def find_trackers
|
||||
ids = Array.wrap(params[:tracker_id])
|
||||
if ids == ['all']
|
||||
@trackers = Tracker.sorted.all
|
||||
@trackers = Tracker.sorted.to_a
|
||||
elsif ids.present?
|
||||
@trackers = Tracker.where(:id => ids).all
|
||||
@trackers = Tracker.where(:id => ids).to_a
|
||||
end
|
||||
@trackers = nil if @trackers.blank?
|
||||
end
|
||||
@@ -135,6 +135,6 @@ class WorkflowsController < ApplicationController
|
||||
if @trackers && @used_statuses_only
|
||||
@statuses = @trackers.map(&:issue_statuses).flatten.uniq.sort.presence
|
||||
end
|
||||
@statuses ||= IssueStatus.sorted.all
|
||||
@statuses ||= IssueStatus.sorted.to_a
|
||||
end
|
||||
end
|
||||
|
||||
@@ -138,9 +138,7 @@ module ApplicationHelper
|
||||
if project.archived?
|
||||
h(project.name)
|
||||
elsif options.key?(:action)
|
||||
ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0."
|
||||
url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
|
||||
link_to project.name, url, html_options
|
||||
raise "#link_to_project no longer accepts :action option in Redmine 3.0"
|
||||
else
|
||||
link_to project.name, project_path(project, options), html_options
|
||||
end
|
||||
@@ -157,13 +155,6 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
|
||||
# Generates a link to a version
|
||||
def link_to_version(version, options = {})
|
||||
return '' unless version && version.is_a?(Version)
|
||||
options = {:title => format_date(version.effective_date)}.merge(options)
|
||||
link_to_if version.visible?, format_version_name(version), version_path(version), options
|
||||
end
|
||||
|
||||
# Helper that formats object for html or text rendering
|
||||
def format_object(object, html=true, &block)
|
||||
if block_given?
|
||||
@@ -185,7 +176,7 @@ module ApplicationHelper
|
||||
when 'Project'
|
||||
html ? link_to_project(object) : object.to_s
|
||||
when 'Version'
|
||||
html ? link_to_version(object) : object.to_s
|
||||
html ? link_to(object.name, version_path(object)) : object.to_s
|
||||
when 'TrueClass'
|
||||
l(:general_text_Yes)
|
||||
when 'FalseClass'
|
||||
@@ -247,7 +238,7 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def format_version_name(version)
|
||||
if !version.shared? || version.project == @project
|
||||
if version.project == @project
|
||||
h(version)
|
||||
else
|
||||
h("#{version.project} - #{version}")
|
||||
@@ -502,7 +493,7 @@ module ApplicationHelper
|
||||
h(Setting.app_title)
|
||||
else
|
||||
b = []
|
||||
ancestors = (@project.root? ? [] : @project.ancestors.visible.all)
|
||||
ancestors = (@project.root? ? [] : @project.ancestors.visible.to_a)
|
||||
if ancestors.any?
|
||||
root = ancestors.shift
|
||||
b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
|
||||
@@ -1217,7 +1208,7 @@ module ApplicationHelper
|
||||
source
|
||||
end
|
||||
end
|
||||
super sources, options
|
||||
super *sources, options
|
||||
end
|
||||
|
||||
# Overrides Rails' image_tag with themes and plugins support.
|
||||
@@ -1250,7 +1241,7 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
super sources, options
|
||||
super *sources, options
|
||||
end
|
||||
|
||||
# TODO: remove this in 2.5.0
|
||||
@@ -1288,12 +1279,7 @@ module ApplicationHelper
|
||||
end
|
||||
|
||||
def sanitize_anchor_name(anchor)
|
||||
if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java'
|
||||
anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
else
|
||||
# TODO: remove when ruby1.8 is no longer supported
|
||||
anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
end
|
||||
anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
|
||||
end
|
||||
|
||||
# Returns the javascript tags that are included in the html layout head
|
||||
|
||||
@@ -30,7 +30,7 @@ module GroupsHelper
|
||||
scope = User.active.sorted.not_in_group(group).like(params[:q])
|
||||
principal_count = scope.count
|
||||
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a
|
||||
|
||||
s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals')
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ module IssuesHelper
|
||||
|
||||
def render_issue_subject_with_tree(issue)
|
||||
s = ''
|
||||
ancestors = issue.root? ? [] : issue.ancestors.visible.all
|
||||
ancestors = issue.root? ? [] : issue.ancestors.visible.to_a
|
||||
ancestors.each do |ancestor|
|
||||
s << '<div>' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id)))
|
||||
end
|
||||
@@ -204,7 +204,7 @@ module IssuesHelper
|
||||
order("#{Query.table_name}.name ASC").
|
||||
# Project specific queries and global queries
|
||||
where(@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]).
|
||||
all
|
||||
to_a
|
||||
end
|
||||
@sidebar_queries
|
||||
end
|
||||
@@ -408,7 +408,7 @@ module IssuesHelper
|
||||
if association
|
||||
record = association.class_name.constantize.find_by_id(id)
|
||||
if record
|
||||
record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding)
|
||||
record.name.force_encoding('UTF-8')
|
||||
return record.name
|
||||
end
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ module MembersHelper
|
||||
scope = Principal.active.sorted.not_member_of(project).like(params[:q])
|
||||
principal_count = scope.count
|
||||
principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page']
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all
|
||||
principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).to_a
|
||||
|
||||
s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals')
|
||||
|
||||
|
||||
@@ -23,11 +23,12 @@ module MyHelper
|
||||
where(:project_id => User.current.projects.map(&:id)).
|
||||
where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt).
|
||||
includes(:project, :tracker, :priority, :assigned_to).
|
||||
all
|
||||
references(:project, :tracker, :priority, :assigned_to).
|
||||
to_a
|
||||
end
|
||||
|
||||
def documents_items
|
||||
Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all
|
||||
Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).to_a
|
||||
end
|
||||
|
||||
def issuesassignedtome_items
|
||||
@@ -35,8 +36,9 @@ module MyHelper
|
||||
where(:assigned_to_id => ([User.current.id] + User.current.group_ids)).
|
||||
limit(10).
|
||||
includes(:status, :project, :tracker, :priority).
|
||||
references(:status, :project, :tracker, :priority).
|
||||
order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC").
|
||||
all
|
||||
to_a
|
||||
end
|
||||
|
||||
def issuesreportedbyme_items
|
||||
@@ -44,12 +46,13 @@ module MyHelper
|
||||
where(:author_id => User.current.id).
|
||||
limit(10).
|
||||
includes(:status, :project, :tracker).
|
||||
references(:status, :project, :tracker).
|
||||
order("#{Issue.table_name}.updated_on DESC").
|
||||
all
|
||||
to_a
|
||||
end
|
||||
|
||||
def issueswatched_items
|
||||
Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all
|
||||
Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).to_a
|
||||
end
|
||||
|
||||
def news_items
|
||||
@@ -57,15 +60,17 @@ module MyHelper
|
||||
where(:project_id => User.current.projects.map(&:id)).
|
||||
limit(10).
|
||||
includes(:project, :author).
|
||||
references(:project, :author).
|
||||
order("#{News.table_name}.created_on DESC").
|
||||
all
|
||||
to_a
|
||||
end
|
||||
|
||||
def timelog_items
|
||||
TimeEntry.
|
||||
where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today).
|
||||
includes(:activity, :project, {:issue => [:tracker, :status]}).
|
||||
joins(:activity, :project, {:issue => [:tracker, :status]}).
|
||||
references(:activity, :project, {:issue => [:tracker, :status]}).
|
||||
order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC").
|
||||
all
|
||||
to_a
|
||||
end
|
||||
end
|
||||
|
||||
@@ -18,6 +18,11 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
module ProjectsHelper
|
||||
def link_to_version(version, options = {})
|
||||
return '' unless version && version.is_a?(Version)
|
||||
link_to_if version.visible?, format_version_name(version), version_path(version), options
|
||||
end
|
||||
|
||||
def project_settings_tabs
|
||||
tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural},
|
||||
{:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural},
|
||||
|
||||
@@ -143,7 +143,7 @@ module QueriesHelper
|
||||
end
|
||||
end
|
||||
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# csv header fields
|
||||
csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) }
|
||||
# csv lines
|
||||
|
||||
@@ -29,7 +29,6 @@ module SearchHelper
|
||||
result << '...'
|
||||
break
|
||||
end
|
||||
words = words.mb_chars
|
||||
if i.even?
|
||||
result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words)
|
||||
else
|
||||
|
||||
@@ -84,7 +84,8 @@ module SortHelper
|
||||
def to_sql
|
||||
sql = @criteria.collect do |k,o|
|
||||
if s = @available_criteria[k]
|
||||
(o ? s.to_a : s.to_a.collect {|c| append_desc(c)})
|
||||
s = [s] unless s.is_a?(Array)
|
||||
(o ? s : s.collect {|c| append_desc(c)})
|
||||
end
|
||||
end.flatten.compact
|
||||
sql.blank? ? nil : sql
|
||||
|
||||
@@ -105,7 +105,7 @@ module TimelogHelper
|
||||
|
||||
def report_to_csv(report)
|
||||
decimal_separator = l(:general_csv_decimal_separator)
|
||||
export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
export = CSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
|
||||
# Column headers
|
||||
headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) }
|
||||
headers += report.periods
|
||||
|
||||
@@ -27,6 +27,7 @@ class Attachment < ActiveRecord::Base
|
||||
validates_length_of :disk_filename, :maximum => 255
|
||||
validates_length_of :description, :maximum => 255
|
||||
validate :validate_max_file_size
|
||||
attr_protected :id
|
||||
|
||||
acts_as_event :title => :filename,
|
||||
:url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}}
|
||||
@@ -34,16 +35,16 @@ class Attachment < ActiveRecord::Base
|
||||
acts_as_activity_provider :type => 'files',
|
||||
:permission => :view_files,
|
||||
:author_key => :author_id,
|
||||
:find_options => {:select => "#{Attachment.table_name}.*",
|
||||
:joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
|
||||
"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 )"}
|
||||
:scope => select("#{Attachment.table_name}.*").
|
||||
joins("LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
|
||||
"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 )")
|
||||
|
||||
acts_as_activity_provider :type => 'documents',
|
||||
:permission => :view_documents,
|
||||
:author_key => :author_id,
|
||||
:find_options => {:select => "#{Attachment.table_name}.*",
|
||||
:joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
|
||||
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"}
|
||||
:scope => select("#{Attachment.table_name}.*").
|
||||
joins("LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " +
|
||||
"LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id")
|
||||
|
||||
cattr_accessor :storage_path
|
||||
@@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files")
|
||||
@@ -74,7 +75,7 @@ class Attachment < ActiveRecord::Base
|
||||
if @temp_file.size > 0
|
||||
if @temp_file.respond_to?(:original_filename)
|
||||
self.filename = @temp_file.original_filename
|
||||
self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding)
|
||||
self.filename.force_encoding("UTF-8")
|
||||
end
|
||||
if @temp_file.respond_to?(:content_type)
|
||||
self.content_type = @temp_file.content_type.to_s.chomp
|
||||
|
||||
@@ -29,6 +29,7 @@ class AuthSource < ActiveRecord::Base
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name
|
||||
validates_length_of :name, :maximum => 60
|
||||
attr_protected :id
|
||||
|
||||
def authenticate(login, password)
|
||||
end
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
class Board < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :project
|
||||
has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC"
|
||||
has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC"
|
||||
has_many :topics, lambda {where("#{Message.table_name}.parent_id IS NULL").order("#{Message.table_name}.created_on DESC")}, :class_name => 'Message'
|
||||
has_many :messages, lambda {order("#{Message.table_name}.created_on DESC")}, :dependent => :destroy
|
||||
belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id
|
||||
acts_as_tree :dependent => :nullify
|
||||
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
|
||||
validates_length_of :name, :maximum => 30
|
||||
validates_length_of :description, :maximum => 255
|
||||
validate :validate_board
|
||||
attr_protected :id
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
|
||||
}
|
||||
|
||||
safe_attributes 'name', 'description', 'parent_id', 'move_to'
|
||||
|
||||
@@ -21,6 +21,7 @@ class Change < ActiveRecord::Base
|
||||
validates_presence_of :changeset_id, :action, :path
|
||||
before_save :init_path
|
||||
before_validation :replace_invalid_utf8_of_path
|
||||
attr_protected :id
|
||||
|
||||
def relative_path
|
||||
changeset.repository.relative_path(path)
|
||||
|
||||
@@ -35,20 +35,23 @@ class Changeset < ActiveRecord::Base
|
||||
:url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}}
|
||||
|
||||
acts_as_searchable :columns => 'comments',
|
||||
:include => {:repository => :project},
|
||||
:scope => preload(:repository => :project),
|
||||
:project_key => "#{Repository.table_name}.project_id",
|
||||
:date_column => 'committed_on'
|
||||
|
||||
acts_as_activity_provider :timestamp => "#{table_name}.committed_on",
|
||||
:author_key => :user_id,
|
||||
:find_options => {:include => [:user, {:repository => :project}]}
|
||||
:scope => preload(:user, {:repository => :project})
|
||||
|
||||
validates_presence_of :repository_id, :revision, :committed_on, :commit_date
|
||||
validates_uniqueness_of :revision, :scope => :repository_id
|
||||
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
|
||||
attr_protected :id
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
|
||||
joins(:repository => :project).
|
||||
references(:repository => :project).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args))
|
||||
}
|
||||
|
||||
after_create :scan_for_issues
|
||||
|
||||
@@ -21,6 +21,7 @@ class Comment < ActiveRecord::Base
|
||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||
|
||||
validates_presence_of :commented, :author, :comments
|
||||
attr_protected :id
|
||||
|
||||
after_create :send_notification
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ class CustomField < ActiveRecord::Base
|
||||
validates_length_of :name, :maximum => 30
|
||||
validates_inclusion_of :field_format, :in => Proc.new { Redmine::FieldFormat.available_formats }
|
||||
validate :validate_custom_field
|
||||
attr_protected :id
|
||||
|
||||
before_validation :set_searchable
|
||||
before_save do |field|
|
||||
@@ -117,7 +118,7 @@ class CustomField < ActiveRecord::Base
|
||||
values = read_attribute(:possible_values)
|
||||
if values.is_a?(Array)
|
||||
values.each do |value|
|
||||
value.force_encoding('UTF-8') if value.respond_to?(:force_encoding)
|
||||
value.force_encoding('UTF-8')
|
||||
end
|
||||
values
|
||||
else
|
||||
@@ -218,7 +219,7 @@ class CustomField < ActiveRecord::Base
|
||||
|
||||
# to move in project_custom_field
|
||||
def self.for_all
|
||||
where(:is_for_all => true).order('position').all
|
||||
where(:is_for_all => true).order('position').to_a
|
||||
end
|
||||
|
||||
def type_name
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
class CustomValue < ActiveRecord::Base
|
||||
belongs_to :custom_field
|
||||
belongs_to :customized, :polymorphic => true
|
||||
attr_protected :id
|
||||
|
||||
def initialize(attributes=nil, *args)
|
||||
super
|
||||
|
||||
@@ -21,19 +21,23 @@ class Document < ActiveRecord::Base
|
||||
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
|
||||
acts_as_attachable :delete_permission => :delete_documents
|
||||
|
||||
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
|
||||
acts_as_searchable :columns => ['title', "#{table_name}.description"],
|
||||
:scope => preload(:project)
|
||||
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
|
||||
:author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) },
|
||||
:url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
|
||||
acts_as_activity_provider :find_options => {:include => :project}
|
||||
acts_as_activity_provider :scope => preload(:project)
|
||||
|
||||
validates_presence_of :project, :title, :category
|
||||
validates_length_of :title, :maximum => 60
|
||||
attr_protected :id
|
||||
|
||||
after_create :send_notification
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args))
|
||||
}
|
||||
|
||||
safe_attributes 'category_id', 'title', 'description'
|
||||
|
||||
@@ -21,6 +21,7 @@ class EnabledModule < ActiveRecord::Base
|
||||
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name, :scope => :project_id
|
||||
attr_protected :id
|
||||
|
||||
after_create :module_enabled
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
class Enumeration < ActiveRecord::Base
|
||||
include Redmine::SubclassFactory
|
||||
|
||||
default_scope :order => "#{Enumeration.table_name}.position ASC"
|
||||
default_scope lambda {order("#{Enumeration.table_name}.position ASC")}
|
||||
|
||||
belongs_to :project
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ class Group < Principal
|
||||
validates_presence_of :lastname
|
||||
validates_uniqueness_of :lastname, :case_sensitive => false
|
||||
validates_length_of :lastname, :maximum => 255
|
||||
attr_protected :id
|
||||
|
||||
before_destroy :remove_references_before_destroy
|
||||
|
||||
@@ -81,7 +82,8 @@ class Group < Principal
|
||||
def user_removed(user)
|
||||
members.each do |member|
|
||||
MemberRole.
|
||||
includes(:member).
|
||||
joins(:member).
|
||||
references(:member).
|
||||
where("#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids).
|
||||
each(&:destroy)
|
||||
end
|
||||
@@ -95,10 +97,6 @@ class Group < Principal
|
||||
super(attr_name, *args)
|
||||
end
|
||||
|
||||
def self.builtin_id(arg)
|
||||
(arg.anonymous? ? GroupAnonymous : GroupNonMember).instance_id
|
||||
end
|
||||
|
||||
def self.anonymous
|
||||
GroupAnonymous.load_instance
|
||||
end
|
||||
|
||||
@@ -23,8 +23,4 @@ class GroupAnonymous < GroupBuiltin
|
||||
def builtin_type
|
||||
"anonymous"
|
||||
end
|
||||
|
||||
def self.instance_id
|
||||
@@instance_id ||= load_instance.id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -37,7 +37,7 @@ class GroupBuiltin < Group
|
||||
class << self
|
||||
def load_instance
|
||||
return nil if self == GroupBuiltin
|
||||
instance = first(:order => 'id') || create_instance
|
||||
instance = order('id').first || create_instance
|
||||
end
|
||||
|
||||
def create_instance
|
||||
|
||||
@@ -23,8 +23,4 @@ class GroupNonMember < GroupBuiltin
|
||||
def builtin_type
|
||||
"non_member"
|
||||
end
|
||||
|
||||
def self.instance_id
|
||||
@@instance_id ||= load_instance.id
|
||||
end
|
||||
end
|
||||
|
||||
@@ -31,15 +31,12 @@ class Issue < ActiveRecord::Base
|
||||
|
||||
has_many :journals, :as => :journalized, :dependent => :destroy
|
||||
has_many :visible_journals,
|
||||
lambda {where(["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false])},
|
||||
:class_name => 'Journal',
|
||||
:as => :journalized,
|
||||
:conditions => Proc.new {
|
||||
["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false]
|
||||
},
|
||||
:readonly => true
|
||||
:as => :journalized
|
||||
|
||||
has_many :time_entries, :dependent => :destroy
|
||||
has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC"
|
||||
has_and_belongs_to_many :changesets, lambda {order("#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC")}
|
||||
|
||||
has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
|
||||
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
|
||||
@@ -49,14 +46,19 @@ class Issue < ActiveRecord::Base
|
||||
acts_as_customizable
|
||||
acts_as_watchable
|
||||
acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
|
||||
:include => [:project, :visible_journals],
|
||||
# sort by id so that limited eager loading doesn't break with postgresql
|
||||
:order_column => "#{table_name}.id"
|
||||
:order_column => "#{table_name}.id",
|
||||
:scope => lambda { joins(:project).
|
||||
joins("LEFT OUTER JOIN #{Journal.table_name} ON #{Journal.table_name}.journalized_type='Issue'" +
|
||||
" AND #{Journal.table_name}.journalized_id = #{Issue.table_name}.id" +
|
||||
" AND (#{Journal.table_name}.private_notes = #{connection.quoted_false}" +
|
||||
" OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))") }
|
||||
|
||||
acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"},
|
||||
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
|
||||
:type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
|
||||
|
||||
acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]},
|
||||
acts_as_activity_provider :scope => preload(:project, :author, :tracker),
|
||||
:author_key => :author_id
|
||||
|
||||
DONE_RATIO_OPTIONS = %w(issue_field issue_status)
|
||||
@@ -72,19 +74,26 @@ class Issue < ActiveRecord::Base
|
||||
validates :start_date, :date => true
|
||||
validates :due_date, :date => true
|
||||
validate :validate_issue, :validate_required_fields
|
||||
attr_protected :id
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Issue.visible_condition(args.shift || User.current, *args))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(Issue.visible_condition(args.shift || User.current, *args))
|
||||
}
|
||||
|
||||
scope :open, lambda {|*args|
|
||||
is_closed = args.size > 0 ? !args.first : false
|
||||
includes(:status).where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
|
||||
joins(:status).
|
||||
references(:status).
|
||||
where("#{IssueStatus.table_name}.is_closed = ?", is_closed)
|
||||
}
|
||||
|
||||
scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") }
|
||||
scope :on_active_project, lambda {
|
||||
includes(:status, :project, :tracker).where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE)
|
||||
}
|
||||
scope :fixed_version, lambda {|versions|
|
||||
ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v}
|
||||
@@ -107,7 +116,7 @@ class Issue < ActiveRecord::Base
|
||||
# Returns a SQL conditions string used to find all issues visible by the specified user
|
||||
def self.visible_condition(user, options={})
|
||||
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
|
||||
if user.logged?
|
||||
if user.id && user.logged?
|
||||
case role.issues_visibility
|
||||
when 'all'
|
||||
nil
|
||||
@@ -351,6 +360,10 @@ class Issue < ActiveRecord::Base
|
||||
# Do not redefine alias chain on reload (see #4838)
|
||||
alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first)
|
||||
|
||||
def attributes=(new_attributes)
|
||||
assign_attributes new_attributes
|
||||
end
|
||||
|
||||
def estimated_hours=(h)
|
||||
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
|
||||
end
|
||||
@@ -423,7 +436,7 @@ class Issue < ActiveRecord::Base
|
||||
def safe_attributes=(attrs, user=User.current)
|
||||
return unless attrs.is_a?(Hash)
|
||||
|
||||
attrs = attrs.dup
|
||||
attrs = attrs.deep_dup
|
||||
|
||||
# Project and Tracker must be set before since new_statuses_allowed_to depends on it.
|
||||
if (p = attrs.delete('project_id')) && safe_attribute?('project_id')
|
||||
@@ -458,14 +471,12 @@ class Issue < ActiveRecord::Base
|
||||
|
||||
if attrs['custom_field_values'].present?
|
||||
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
|
||||
# TODO: use #select when ruby1.8 support is dropped
|
||||
attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| !editable_custom_field_ids.include?(k.to_s)}
|
||||
attrs['custom_field_values'].select! {|k, v| editable_custom_field_ids.include?(k.to_s)}
|
||||
end
|
||||
|
||||
if attrs['custom_fields'].present?
|
||||
editable_custom_field_ids = editable_custom_field_values(user).map {|v| v.custom_field_id.to_s}
|
||||
# TODO: use #select when ruby1.8 support is dropped
|
||||
attrs['custom_fields'] = attrs['custom_fields'].reject {|c| !editable_custom_field_ids.include?(c['id'].to_s)}
|
||||
attrs['custom_fields'].select! {|c| editable_custom_field_ids.include?(c['id'].to_s)}
|
||||
end
|
||||
|
||||
# mass-assignment security bypass
|
||||
@@ -733,7 +744,7 @@ class Issue < ActiveRecord::Base
|
||||
def assignable_versions
|
||||
return @assignable_versions if @assignable_versions
|
||||
|
||||
versions = project.shared_versions.open.all
|
||||
versions = project.shared_versions.open.to_a
|
||||
if fixed_version
|
||||
if fixed_version_id_changed?
|
||||
# nothing to do
|
||||
@@ -879,10 +890,14 @@ class Issue < ActiveRecord::Base
|
||||
if issues.any?
|
||||
issue_ids = issues.map(&:id)
|
||||
# Relations with issue_from in given issues and visible issue_to
|
||||
relations_from = IssueRelation.includes(:issue_to => [:status, :project]).where(visible_condition(user)).where(:issue_from_id => issue_ids).all
|
||||
relations_from = IssueRelation.joins(:issue_to => :project).
|
||||
references(:issue_to => :project).
|
||||
where(visible_condition(user)).where(:issue_from_id => issue_ids).to_a
|
||||
# Relations with issue_to in given issues and visible issue_from
|
||||
relations_to = IssueRelation.includes(:issue_from => [:status, :project]).where(visible_condition(user)).where(:issue_to_id => issue_ids).all
|
||||
|
||||
relations_to = IssueRelation.joins(:issue_from => :project).
|
||||
references(:issue_from => :project).
|
||||
where(visible_condition(user)).
|
||||
where(:issue_to_id => issue_ids).to_a
|
||||
issues.each do |issue|
|
||||
relations =
|
||||
relations_from.select {|relation| relation.issue_from_id == issue.id} +
|
||||
@@ -1121,6 +1136,7 @@ class Issue < ActiveRecord::Base
|
||||
def parent_issue_id=(arg)
|
||||
s = arg.to_s.strip.presence
|
||||
if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1]))
|
||||
@parent_issue.id
|
||||
@invalid_parent_issue_id = nil
|
||||
elsif s.blank?
|
||||
@parent_issue = nil
|
||||
@@ -1349,7 +1365,7 @@ class Issue < ActiveRecord::Base
|
||||
self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id)
|
||||
cond = ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]
|
||||
self.class.base_class.select('id').lock(true).where(cond)
|
||||
offset = right_most_bound + 1 - lft
|
||||
offset = rdm_right_most_bound + 1 - lft
|
||||
Issue.where(cond).
|
||||
update_all(["root_id = ?, lft = lft + ?, rgt = rgt + ?", root_id, offset, offset])
|
||||
end
|
||||
@@ -1367,6 +1383,14 @@ class Issue < ActiveRecord::Base
|
||||
recalculate_attributes_for(former_parent_id) if former_parent_id
|
||||
end
|
||||
|
||||
def rdm_right_most_bound
|
||||
right_most_node =
|
||||
self.class.base_class.unscoped.
|
||||
order("#{quoted_right_column_full_name} desc").limit(1).lock(true).first
|
||||
right_most_node ? (right_most_node[right_column_name] || 0 ) : 0
|
||||
end
|
||||
private :rdm_right_most_bound
|
||||
|
||||
def update_parent_attributes
|
||||
recalculate_attributes_for(parent_id) if parent_id
|
||||
end
|
||||
@@ -1395,7 +1419,7 @@ class Issue < ActiveRecord::Base
|
||||
end
|
||||
done = p.leaves.joins(:status).
|
||||
sum("COALESCE(CASE WHEN estimated_hours > 0 THEN estimated_hours ELSE NULL END, #{average}) " +
|
||||
"* (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
|
||||
"* (CASE WHEN is_closed = #{self.class.connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f
|
||||
progress = done / (average * leaves_count)
|
||||
p.done_ratio = progress.round
|
||||
end
|
||||
@@ -1415,7 +1439,8 @@ class Issue < ActiveRecord::Base
|
||||
def self.update_versions(conditions=nil)
|
||||
# Only need to update issues with a fixed_version from
|
||||
# a different project and that is not systemwide shared
|
||||
Issue.includes(:project, :fixed_version).
|
||||
Issue.joins(:project, :fixed_version).
|
||||
references(:version, :fixed_version).
|
||||
where("#{Issue.table_name}.fixed_version_id IS NOT NULL" +
|
||||
" AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" +
|
||||
" AND #{Version.table_name}.sharing <> 'system'").
|
||||
|
||||
@@ -24,6 +24,7 @@ class IssueCategory < ActiveRecord::Base
|
||||
validates_presence_of :name
|
||||
validates_uniqueness_of :name, :scope => [:project_id]
|
||||
validates_length_of :name, :maximum => 30
|
||||
attr_protected :id
|
||||
|
||||
safe_attributes 'name', 'assigned_to_id'
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ class IssueCustomField < CustomField
|
||||
sql = super
|
||||
id_column ||= id
|
||||
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})"
|
||||
project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" +
|
||||
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})" +
|
||||
" 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})"
|
||||
|
||||
"((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
|
||||
|
||||
@@ -45,7 +45,9 @@ class IssueQuery < Query
|
||||
scope :visible, lambda {|*args|
|
||||
user = args.shift || User.current
|
||||
base = Project.allowed_to_condition(user, :view_issues, *args)
|
||||
scope = includes(:project).where("#{table_name}.project_id IS NULL OR (#{base})")
|
||||
scope = joins("LEFT OUTER JOIN #{Project.table_name} ON #{table_name}.project_id = #{Project.table_name}.id").
|
||||
references(:project).
|
||||
where("#{table_name}.project_id IS NULL OR (#{base})")
|
||||
|
||||
if user.admin?
|
||||
scope.where("#{table_name}.visibility <> ? OR #{table_name}.user_id = ?", VISIBILITY_PRIVATE, user.id)
|
||||
@@ -132,17 +134,17 @@ class IssueQuery < Query
|
||||
if project
|
||||
principals += project.principals.sort
|
||||
unless project.leaf?
|
||||
subprojects = project.descendants.visible.all
|
||||
subprojects = project.descendants.visible.to_a
|
||||
principals += Principal.member_of(subprojects)
|
||||
end
|
||||
versions = project.shared_versions.all
|
||||
categories = project.issue_categories.all
|
||||
versions = project.shared_versions.to_a
|
||||
categories = project.issue_categories.to_a
|
||||
issue_custom_fields = project.all_issue_custom_fields
|
||||
else
|
||||
if all_projects.any?
|
||||
principals += Principal.member_of(all_projects)
|
||||
end
|
||||
versions = Version.visible.where(:sharing => 'system').all
|
||||
versions = Version.visible.where(:sharing => 'system').to_a
|
||||
issue_custom_fields = IssueCustomField.where(:is_for_all => true)
|
||||
end
|
||||
principals.uniq!
|
||||
@@ -339,7 +341,7 @@ class IssueQuery < Query
|
||||
scope = scope.preload(:author)
|
||||
end
|
||||
|
||||
issues = scope.all
|
||||
issues = scope.to_a
|
||||
|
||||
if has_column?(:spent_hours)
|
||||
Issue.load_visible_spent_hours(issues)
|
||||
@@ -360,12 +362,13 @@ class IssueQuery < Query
|
||||
joins(:status, :project).
|
||||
where(statement).
|
||||
includes(([:status, :project] + (options[:include] || [])).uniq).
|
||||
references(([:status, :project] + (options[:include] || [])).uniq).
|
||||
where(options[:conditions]).
|
||||
order(order_option).
|
||||
joins(joins_for_order_statement(order_option.join(','))).
|
||||
limit(options[:limit]).
|
||||
offset(options[:offset]).
|
||||
find_ids
|
||||
pluck(:id)
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
end
|
||||
@@ -380,7 +383,7 @@ class IssueQuery < Query
|
||||
limit(options[:limit]).
|
||||
offset(options[:offset]).
|
||||
preload(:details, :user, {:issue => [:project, :author, :tracker, :status]}).
|
||||
all
|
||||
to_a
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
end
|
||||
@@ -392,7 +395,8 @@ class IssueQuery < Query
|
||||
where(project_statement).
|
||||
where(options[:conditions]).
|
||||
includes(:project).
|
||||
all
|
||||
references(:project).
|
||||
to_a
|
||||
rescue ::ActiveRecord::StatementInvalid => e
|
||||
raise StatementInvalid.new(e.message)
|
||||
end
|
||||
@@ -411,7 +415,7 @@ class IssueQuery < Query
|
||||
groups = Group.givable
|
||||
operator = '!' # Override the operator since we want to find by assigned_to
|
||||
else
|
||||
groups = Group.where(:id => value).all
|
||||
groups = Group.where(:id => value).to_a
|
||||
end
|
||||
groups ||= []
|
||||
|
||||
@@ -431,7 +435,7 @@ class IssueQuery < Query
|
||||
" WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))"
|
||||
when "=", "!"
|
||||
role_cond = value.any? ?
|
||||
"#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" :
|
||||
"#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")" :
|
||||
"1=0"
|
||||
|
||||
sw = operator == "!" ? 'NOT' : ''
|
||||
@@ -443,7 +447,7 @@ class IssueQuery < Query
|
||||
|
||||
def sql_for_is_private_field(field, operator, value)
|
||||
op = (operator == "=" ? 'IN' : 'NOT IN')
|
||||
va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',')
|
||||
va = value.map {|v| v == '0' ? self.class.connection.quoted_false : self.class.connection.quoted_true}.uniq.join(',')
|
||||
|
||||
"#{Issue.table_name}.is_private #{op} (#{va})"
|
||||
end
|
||||
@@ -462,14 +466,14 @@ class IssueQuery < Query
|
||||
sql = case operator
|
||||
when "*", "!*"
|
||||
op = (operator == "*" ? 'IN' : 'NOT IN')
|
||||
"#{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)}')"
|
||||
"#{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)}')"
|
||||
when "=", "!"
|
||||
op = (operator == "=" ? 'IN' : 'NOT IN')
|
||||
"#{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})"
|
||||
"#{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})"
|
||||
when "=p", "=!p", "!p"
|
||||
op = (operator == "!p" ? 'NOT IN' : 'IN')
|
||||
comp = (operator == "=!p" ? '<>' : '=')
|
||||
"#{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})"
|
||||
"#{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})"
|
||||
end
|
||||
|
||||
if relation_options[:sym] == field && !options[:reverse]
|
||||
|
||||
@@ -27,6 +27,7 @@ class IssueStatus < ActiveRecord::Base
|
||||
validates_uniqueness_of :name
|
||||
validates_length_of :name, :maximum => 30
|
||||
validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true
|
||||
attr_protected :id
|
||||
|
||||
scope :sorted, lambda { order("#{table_name}.position ASC") }
|
||||
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
|
||||
@@ -79,7 +80,7 @@ class IssueStatus < ActiveRecord::Base
|
||||
includes(:new_status).
|
||||
where(["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})",
|
||||
{:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false}
|
||||
]).all.
|
||||
]).to_a.
|
||||
map(&:new_status).compact.sort
|
||||
else
|
||||
[]
|
||||
|
||||
@@ -24,6 +24,7 @@ class Journal < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
|
||||
attr_accessor :indice
|
||||
attr_protected :id
|
||||
|
||||
acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" },
|
||||
:description => :notes,
|
||||
@@ -34,17 +35,18 @@ class Journal < ActiveRecord::Base
|
||||
|
||||
acts_as_activity_provider :type => 'issues',
|
||||
:author_key => :user_id,
|
||||
:find_options => {:include => [{:issue => :project}, :details, :user],
|
||||
:conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
|
||||
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
|
||||
:scope => preload({:issue => :project}, :user).
|
||||
joins("LEFT OUTER JOIN #{JournalDetail.table_name} ON #{JournalDetail.table_name}.journal_id = #{Journal.table_name}.id").
|
||||
where("#{Journal.table_name}.journalized_type = 'Issue' AND" +
|
||||
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')")
|
||||
|
||||
before_create :split_private_notes
|
||||
after_create :send_notification
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
user = args.shift || User.current
|
||||
|
||||
includes(:issue => :project).
|
||||
joins(:issue => :project).
|
||||
references(:project).
|
||||
where(Issue.visible_condition(user, *args)).
|
||||
where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false)
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
class JournalDetail < ActiveRecord::Base
|
||||
belongs_to :journal
|
||||
before_save :normalize_values
|
||||
attr_protected :id
|
||||
|
||||
def custom_field
|
||||
if property == 'cf'
|
||||
|
||||
@@ -42,7 +42,7 @@ class MailHandler < ActionMailer::Base
|
||||
@@handler_options[:no_notification] = (@@handler_options[:no_notification].to_s == '1')
|
||||
@@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1')
|
||||
|
||||
email.force_encoding('ASCII-8BIT') if email.respond_to?(:force_encoding)
|
||||
email.force_encoding('ASCII-8BIT')
|
||||
super(email)
|
||||
end
|
||||
|
||||
@@ -417,7 +417,7 @@ class MailHandler < ActionMailer::Base
|
||||
end
|
||||
|
||||
parts.reject! do |part|
|
||||
part.header[:content_disposition].try(:disposition_type) == 'attachment'
|
||||
part.attachment?
|
||||
end
|
||||
|
||||
@plain_text_body = parts.map do |p|
|
||||
|
||||
@@ -25,6 +25,7 @@ class Member < ActiveRecord::Base
|
||||
validates_presence_of :principal, :project
|
||||
validates_uniqueness_of :user_id, :scope => :project_id
|
||||
validate :validate_role
|
||||
attr_protected :id
|
||||
|
||||
before_destroy :set_issue_category_nil
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ class MemberRole < ActiveRecord::Base
|
||||
|
||||
validates_presence_of :role
|
||||
validate :validate_role_member
|
||||
attr_protected :id
|
||||
|
||||
def validate_role_member
|
||||
errors.add :role_id, :invalid if role && !role.member?
|
||||
|
||||
@@ -22,9 +22,10 @@ class Message < ActiveRecord::Base
|
||||
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
|
||||
acts_as_attachable
|
||||
belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
|
||||
attr_protected :id
|
||||
|
||||
acts_as_searchable :columns => ['subject', 'content'],
|
||||
:include => {:board => :project},
|
||||
:scope => preload(:board => :project),
|
||||
:project_key => "#{Board.table_name}.project_id",
|
||||
:date_column => "#{table_name}.created_on"
|
||||
acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
|
||||
@@ -34,7 +35,7 @@ class Message < ActiveRecord::Base
|
||||
:url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} :
|
||||
{:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})}
|
||||
|
||||
acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]},
|
||||
acts_as_activity_provider :scope => preload({:board => :project}, :author),
|
||||
:author_key => :author_id
|
||||
acts_as_watchable
|
||||
|
||||
@@ -48,7 +49,9 @@ class Message < ActiveRecord::Base
|
||||
after_create :send_notification
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:board => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
|
||||
joins(:board => :project).
|
||||
references(:board => :project).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args))
|
||||
}
|
||||
|
||||
safe_attributes 'subject', 'content'
|
||||
|
||||
@@ -19,16 +19,18 @@ class News < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :project
|
||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||
has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
|
||||
has_many :comments, lambda {order("created_on")}, :as => :commented, :dependent => :delete_all
|
||||
|
||||
validates_presence_of :title, :description
|
||||
validates_length_of :title, :maximum => 60
|
||||
validates_length_of :summary, :maximum => 255
|
||||
attr_protected :id
|
||||
|
||||
acts_as_attachable :delete_permission => :manage_news
|
||||
acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
|
||||
acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"],
|
||||
:scope => preload(:project)
|
||||
acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
|
||||
acts_as_activity_provider :find_options => {:include => [:project, :author]},
|
||||
acts_as_activity_provider :scope => preload(:project, :author),
|
||||
:author_key => :author_id
|
||||
acts_as_watchable
|
||||
|
||||
@@ -36,7 +38,9 @@ class News < ActiveRecord::Base
|
||||
after_create :send_notification
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
|
||||
joins(:project).
|
||||
references([:author, :project]).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args))
|
||||
}
|
||||
|
||||
safe_attributes 'title', 'summary', 'description'
|
||||
@@ -68,7 +72,7 @@ class News < ActiveRecord::Base
|
||||
|
||||
# returns latest news for projects visible by user
|
||||
def self.latest(user = User.current, count = 5)
|
||||
visible(user).includes([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).all
|
||||
visible(user).joins([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).to_a
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -25,11 +25,13 @@ class Principal < ActiveRecord::Base
|
||||
STATUS_LOCKED = 3
|
||||
|
||||
has_many :members, :foreign_key => 'user_id', :dependent => :destroy
|
||||
has_many :memberships, :class_name => 'Member',
|
||||
:foreign_key => 'user_id',
|
||||
:include => [:project, :roles],
|
||||
:conditions => "#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}",
|
||||
:order => "#{Project.table_name}.name"
|
||||
has_many :memberships,
|
||||
lambda {preload(:project, :roles).
|
||||
joins(:project).
|
||||
where("#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}").
|
||||
order("#{Project.table_name}.name")},
|
||||
:class_name => 'Member',
|
||||
:foreign_key => 'user_id'
|
||||
has_many :projects, :through => :memberships
|
||||
has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify
|
||||
|
||||
@@ -56,8 +58,8 @@ class Principal < ActiveRecord::Base
|
||||
|
||||
# Principals that are members of a collection of projects
|
||||
scope :member_of, lambda {|projects|
|
||||
projects = [projects] unless projects.is_a?(Array)
|
||||
if projects.empty?
|
||||
projects = [projects] if projects.is_a?(Project)
|
||||
if projects.blank?
|
||||
where("1=0")
|
||||
else
|
||||
ids = projects.map(&:id)
|
||||
|
||||
@@ -28,31 +28,35 @@ class Project < ActiveRecord::Base
|
||||
|
||||
# Specific overridden Activities
|
||||
has_many :time_entry_activities
|
||||
has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
|
||||
has_many :members,
|
||||
lambda { joins(:principal, :roles).
|
||||
references(:principal, :roles).
|
||||
where("#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}") }
|
||||
has_many :memberships, :class_name => 'Member'
|
||||
has_many :member_principals, :class_name => 'Member',
|
||||
:include => :principal,
|
||||
:conditions => "#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}"
|
||||
|
||||
has_many :member_principals,
|
||||
lambda { joins(:principal).
|
||||
references(:principal).
|
||||
where("#{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}")},
|
||||
:class_name => 'Member'
|
||||
has_many :enabled_modules, :dependent => :delete_all
|
||||
has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position"
|
||||
has_many :issues, :dependent => :destroy, :include => [:status, :tracker]
|
||||
has_and_belongs_to_many :trackers, lambda {order("#{Tracker.table_name}.position")}
|
||||
has_many :issues, :dependent => :destroy
|
||||
has_many :issue_changes, :through => :issues, :source => :journals
|
||||
has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
|
||||
has_many :versions, lambda {order("#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC")}, :dependent => :destroy
|
||||
has_many :time_entries, :dependent => :destroy
|
||||
has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all
|
||||
has_many :documents, :dependent => :destroy
|
||||
has_many :news, :dependent => :destroy, :include => :author
|
||||
has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
|
||||
has_many :boards, :dependent => :destroy, :order => "position ASC"
|
||||
has_one :repository, :conditions => ["is_default = ?", true]
|
||||
has_many :news, lambda {includes(:author)}, :dependent => :destroy
|
||||
has_many :issue_categories, lambda {order("#{IssueCategory.table_name}.name")}, :dependent => :delete_all
|
||||
has_many :boards, lambda {order("position ASC")}, :dependent => :destroy
|
||||
has_one :repository, lambda {where(["is_default = ?", true])}
|
||||
has_many :repositories, :dependent => :destroy
|
||||
has_many :changesets, :through => :repository
|
||||
has_one :wiki, :dependent => :destroy
|
||||
# Custom field for the project issues
|
||||
has_and_belongs_to_many :issue_custom_fields,
|
||||
lambda {order("#{CustomField.table_name}.position")},
|
||||
:class_name => 'IssueCustomField',
|
||||
:order => "#{CustomField.table_name}.position",
|
||||
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
|
||||
:association_foreign_key => 'custom_field_id'
|
||||
|
||||
@@ -126,9 +130,9 @@ class Project < ActiveRecord::Base
|
||||
if !initialized.key?('trackers') && !initialized.key?('tracker_ids')
|
||||
default = Setting.default_projects_tracker_ids
|
||||
if default.is_a?(Array)
|
||||
self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.all
|
||||
self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.to_a
|
||||
else
|
||||
self.trackers = Tracker.sorted.all
|
||||
self.trackers = Tracker.sorted.to_a
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -144,7 +148,7 @@ class Project < ActiveRecord::Base
|
||||
# returns latest created projects
|
||||
# non public projects will be returned only if user is a member of those
|
||||
def self.latest(user=nil, count=5)
|
||||
visible(user).limit(count).order("created_on DESC").all
|
||||
visible(user).limit(count).order("created_on DESC").to_a
|
||||
end
|
||||
|
||||
# Returns true if the project is visible to +user+ or to the current user.
|
||||
@@ -212,9 +216,9 @@ class Project < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def override_roles(role)
|
||||
@override_members ||= memberships.where(:user_id => [GroupAnonymous.instance_id, GroupNonMember.instance_id]).all
|
||||
member = @override_members.detect {|m| role.anonymous? ^ (m.user_id == GroupNonMember.instance_id)}
|
||||
member ? member.roles : [role]
|
||||
group_class = role.anonymous? ? GroupAnonymous : GroupNonMember
|
||||
member = member_principals.where("#{Principal.table_name}.type = ?", group_class.name).first
|
||||
member ? member.roles.to_a : [role]
|
||||
end
|
||||
|
||||
def principals
|
||||
@@ -364,7 +368,7 @@ class Project < ActiveRecord::Base
|
||||
# by the current user
|
||||
def allowed_parents
|
||||
return @allowed_parents if @allowed_parents
|
||||
@allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).all
|
||||
@allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).to_a
|
||||
@allowed_parents = @allowed_parents - self_and_descendants
|
||||
if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
|
||||
@allowed_parents << nil
|
||||
@@ -435,11 +439,12 @@ class Project < ActiveRecord::Base
|
||||
@rolled_up_trackers ||=
|
||||
Tracker.
|
||||
joins(:projects).
|
||||
references(:project).
|
||||
joins("JOIN #{EnabledModule.table_name} ON #{EnabledModule.table_name}.project_id = #{Project.table_name}.id AND #{EnabledModule.table_name}.name = 'issue_tracking'").
|
||||
select("DISTINCT #{Tracker.table_name}.*").
|
||||
where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt).
|
||||
sorted.
|
||||
all
|
||||
to_a
|
||||
end
|
||||
|
||||
# Closes open and locked project versions that are completed
|
||||
@@ -457,7 +462,8 @@ class Project < ActiveRecord::Base
|
||||
def rolled_up_versions
|
||||
@rolled_up_versions ||=
|
||||
Version.
|
||||
includes(:project).
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> ?", lft, rgt, STATUS_ARCHIVED)
|
||||
end
|
||||
|
||||
@@ -465,13 +471,17 @@ class Project < ActiveRecord::Base
|
||||
def shared_versions
|
||||
if new_record?
|
||||
Version.
|
||||
includes(:project).
|
||||
joins(:project).
|
||||
references(:project).
|
||||
preload(:project).
|
||||
where("#{Project.table_name}.status <> ? AND #{Version.table_name}.sharing = 'system'", STATUS_ARCHIVED)
|
||||
else
|
||||
@shared_versions ||= begin
|
||||
r = root? ? self : root
|
||||
Version.
|
||||
includes(:project).
|
||||
joins(:project).
|
||||
references(:project).
|
||||
preload(:project).
|
||||
where("#{Project.table_name}.id = #{id}" +
|
||||
" OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" +
|
||||
" #{Version.table_name}.sharing = 'system'" +
|
||||
@@ -497,7 +507,7 @@ class Project < ActiveRecord::Base
|
||||
# Deletes all project's members
|
||||
def delete_all_members
|
||||
me, mr = Member.table_name, MemberRole.table_name
|
||||
connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
|
||||
self.class.connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})")
|
||||
Member.delete_all(['project_id = ?', id])
|
||||
end
|
||||
|
||||
@@ -728,7 +738,7 @@ class Project < ActiveRecord::Base
|
||||
project = project.is_a?(Project) ? project : Project.find(project)
|
||||
|
||||
to_be_copied = %w(wiki versions issue_categories issues members queries boards)
|
||||
to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil?
|
||||
to_be_copied = to_be_copied & Array.wrap(options[:only]) unless options[:only].nil?
|
||||
|
||||
Project.transaction do
|
||||
if save
|
||||
@@ -740,6 +750,7 @@ class Project < ActiveRecord::Base
|
||||
save
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
# Returns a new unsaved Project instance with attributes copied from +project+
|
||||
@@ -958,11 +969,10 @@ class Project < ActiveRecord::Base
|
||||
def copy_queries(project)
|
||||
project.queries.each do |query|
|
||||
new_query = IssueQuery.new
|
||||
new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria", "user_id", "type")
|
||||
new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
|
||||
new_query.sort_criteria = query.sort_criteria if query.sort_criteria
|
||||
new_query.project = self
|
||||
new_query.user_id = query.user_id
|
||||
new_query.role_ids = query.role_ids if query.visibility == IssueQuery::VISIBILITY_ROLES
|
||||
self.queries << new_query
|
||||
end
|
||||
end
|
||||
|
||||
@@ -288,7 +288,7 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def trackers
|
||||
@trackers ||= project.nil? ? Tracker.sorted.all : project.rolled_up_trackers
|
||||
@trackers ||= project.nil? ? Tracker.sorted.to_a : project.rolled_up_trackers
|
||||
end
|
||||
|
||||
# Returns a hash of localized labels for all filter operators
|
||||
@@ -306,7 +306,7 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def all_projects
|
||||
@all_projects ||= Project.visible.all
|
||||
@all_projects ||= Project.visible.to_a
|
||||
end
|
||||
|
||||
def all_projects_values
|
||||
@@ -655,7 +655,7 @@ class Query < ActiveRecord::Base
|
||||
sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}"
|
||||
end
|
||||
else
|
||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + ")"
|
||||
end
|
||||
else
|
||||
# IN an empty set
|
||||
@@ -663,7 +663,7 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
when "!"
|
||||
if value.any?
|
||||
sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
|
||||
sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{self.class.connection.quote_string(val)}'"}.join(",") + "))"
|
||||
else
|
||||
# NOT IN an empty set
|
||||
sql = "1=1"
|
||||
@@ -705,9 +705,9 @@ class Query < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
when "o"
|
||||
sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id"
|
||||
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"
|
||||
when "c"
|
||||
sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id"
|
||||
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"
|
||||
when "><t-"
|
||||
# between today - n days and today
|
||||
sql = relative_date_clause(db_table, db_field, - value.first.to_i, 0)
|
||||
@@ -769,9 +769,9 @@ class Query < ActiveRecord::Base
|
||||
date = Date.today
|
||||
sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year)
|
||||
when "~"
|
||||
sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
|
||||
sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
|
||||
when "!~"
|
||||
sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
|
||||
sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{self.class.connection.quote_string(value.first.to_s.downcase)}%'"
|
||||
else
|
||||
raise "Unknown query operator #{operator}"
|
||||
end
|
||||
@@ -834,7 +834,7 @@ class Query < ActiveRecord::Base
|
||||
if self.class.default_timezone == :utc
|
||||
from = from.utc
|
||||
end
|
||||
s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from)])
|
||||
s << ("#{table}.#{field} > '%s'" % [self.class.connection.quoted_date(from)])
|
||||
end
|
||||
if to
|
||||
if to.is_a?(Date)
|
||||
@@ -843,7 +843,7 @@ class Query < ActiveRecord::Base
|
||||
if self.class.default_timezone == :utc
|
||||
to = to.utc
|
||||
end
|
||||
s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to)])
|
||||
s << ("#{table}.#{field} <= '%s'" % [self.class.connection.quoted_date(to)])
|
||||
end
|
||||
s.join(' AND ')
|
||||
end
|
||||
|
||||
@@ -25,7 +25,7 @@ class Repository < ActiveRecord::Base
|
||||
IDENTIFIER_MAX_LENGTH = 255
|
||||
|
||||
belongs_to :project
|
||||
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
|
||||
has_many :changesets, lambda{order("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC")}
|
||||
has_many :filechanges, :class_name => 'Change', :through => :changesets
|
||||
|
||||
serialize :extra_info
|
||||
@@ -45,6 +45,7 @@ class Repository < ActiveRecord::Base
|
||||
validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true
|
||||
# Checks if the SCM is enabled when creating a repository
|
||||
validate :repo_create_validation, :on => :create
|
||||
attr_protected :id
|
||||
|
||||
safe_attributes 'identifier',
|
||||
'login',
|
||||
@@ -264,7 +265,7 @@ class Repository < ActiveRecord::Base
|
||||
reorder("#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC").
|
||||
limit(limit).
|
||||
preload(:user).
|
||||
all
|
||||
to_a
|
||||
else
|
||||
filechanges.
|
||||
where("path = ?", path.with_leading_slash).
|
||||
@@ -313,7 +314,8 @@ class Repository < ActiveRecord::Base
|
||||
return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
|
||||
|
||||
user = nil
|
||||
c = changesets.where(:committer => committer).includes(:user).first
|
||||
c = changesets.where(:committer => committer).
|
||||
includes(:user).references(:user).first
|
||||
if c && c.user
|
||||
user = c.user
|
||||
elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
|
||||
@@ -484,10 +486,10 @@ class Repository < ActiveRecord::Base
|
||||
ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}"
|
||||
cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}"
|
||||
|
||||
connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
|
||||
self.class.connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
self.class.connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
self.class.connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})")
|
||||
self.class.connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}")
|
||||
clear_extra_info_of_changesets
|
||||
end
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ class Repository::Cvs < Repository
|
||||
# Need to retrieve existing revision numbers to sort them as integers
|
||||
sql = "SELECT revision FROM #{Changeset.table_name} "
|
||||
sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'"
|
||||
@current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0)
|
||||
@current_revision_number ||= (self.class.connection.select_values(sql).collect(&:to_i).max || 0)
|
||||
@current_revision_number += 1
|
||||
end
|
||||
end
|
||||
|
||||
@@ -241,7 +241,7 @@ class Repository::Git < Repository
|
||||
def latest_changesets(path,rev,limit=10)
|
||||
revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false)
|
||||
return [] if revisions.nil? || revisions.empty?
|
||||
changesets.where(:scmid => revisions.map {|c| c.scmid}).all
|
||||
changesets.where(:scmid => revisions.map {|c| c.scmid}).to_a
|
||||
end
|
||||
|
||||
def clear_extra_info_of_changesets
|
||||
|
||||
@@ -20,7 +20,7 @@ require 'redmine/scm/adapters/mercurial_adapter'
|
||||
class Repository::Mercurial < Repository
|
||||
# sort changesets by revision number
|
||||
has_many :changesets,
|
||||
:order => "#{Changeset.table_name}.id DESC",
|
||||
lambda {order("#{Changeset.table_name}.id DESC")},
|
||||
:foreign_key => 'repository_id'
|
||||
|
||||
attr_protected :root_url
|
||||
@@ -117,9 +117,10 @@ class Repository::Mercurial < Repository
|
||||
changesets.
|
||||
includes(:user).
|
||||
where(latest_changesets_cond(path, rev, limit)).
|
||||
references(:user).
|
||||
limit(limit).
|
||||
order("#{Changeset.table_name}.id DESC").
|
||||
all
|
||||
to_a
|
||||
end
|
||||
|
||||
def is_short_id_in_db?
|
||||
|
||||
@@ -42,7 +42,7 @@ class Repository::Subversion < Repository
|
||||
revisions = scm.revisions(path, rev, nil, :limit => limit)
|
||||
if revisions
|
||||
identifiers = revisions.collect(&:identifier).compact
|
||||
changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).all
|
||||
changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).to_a
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@@ -166,7 +166,7 @@ class Role < ActiveRecord::Base
|
||||
|
||||
# Find all the roles that can be given to a project member
|
||||
def self.find_all_givable
|
||||
Role.givable.all
|
||||
Role.givable.to_a
|
||||
end
|
||||
|
||||
# Return the builtin 'non member' role. If the role doesn't exist,
|
||||
|
||||
@@ -86,6 +86,7 @@ class Setting < ActiveRecord::Base
|
||||
validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting|
|
||||
(s = @@available_settings[setting.name]) && s['format'] == 'int'
|
||||
}
|
||||
attr_protected :id
|
||||
|
||||
# Hash used to cache setting values
|
||||
@cached_settings = {}
|
||||
@@ -142,6 +143,7 @@ END_SRC
|
||||
def self.set_from_params(name, params)
|
||||
params = params.dup
|
||||
params.delete_if {|v| v.blank? } if params.is_a?(Array)
|
||||
params.symbolize_keys! if params.is_a?(Hash)
|
||||
|
||||
m = "#{name}_from_params"
|
||||
if respond_to? m
|
||||
|
||||
@@ -35,7 +35,7 @@ class TimeEntry < ActiveRecord::Base
|
||||
|
||||
acts_as_activity_provider :timestamp => "#{table_name}.created_on",
|
||||
:author_key => :user_id,
|
||||
:find_options => {:include => :project}
|
||||
:scope => preload(:project)
|
||||
|
||||
validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
|
||||
validates_numericality_of :hours, :allow_nil => true, :message => :invalid
|
||||
@@ -45,13 +45,19 @@ class TimeEntry < ActiveRecord::Base
|
||||
validate :validate_time_entry
|
||||
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args))
|
||||
}
|
||||
scope :on_issue, lambda {|issue|
|
||||
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}")
|
||||
joins(:issue).
|
||||
references(:issue).
|
||||
where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}")
|
||||
}
|
||||
scope :on_project, lambda {|project, include_subprojects|
|
||||
includes(:project).where(project.project_condition(include_subprojects))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(project.project_condition(include_subprojects))
|
||||
}
|
||||
scope :spent_between, lambda {|from, to|
|
||||
if from && to
|
||||
|
||||
@@ -42,7 +42,7 @@ class TimeEntryQuery < Query
|
||||
if project
|
||||
principals += project.principals.sort
|
||||
unless project.leaf?
|
||||
subprojects = project.descendants.visible.all
|
||||
subprojects = project.descendants.visible.to_a
|
||||
if subprojects.any?
|
||||
add_available_filter "subproject_id",
|
||||
:type => :list_subprojects,
|
||||
@@ -109,7 +109,8 @@ class TimeEntryQuery < Query
|
||||
where(statement).
|
||||
order(order_option).
|
||||
joins(joins_for_order_statement(order_option.join(','))).
|
||||
includes(:activity)
|
||||
includes(:activity).
|
||||
references(:activity)
|
||||
end
|
||||
|
||||
def sql_for_activity_id_field(field, operator, value)
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
class Token < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
validates_uniqueness_of :value
|
||||
attr_protected :id
|
||||
|
||||
before_create :delete_previous_tokens, :generate_new_token
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ class Tracker < ActiveRecord::Base
|
||||
connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE tracker_id = #{id} AND type = 'WorkflowTransition'").
|
||||
flatten.
|
||||
uniq
|
||||
@issue_statuses = IssueStatus.where(:id => ids).all.sort
|
||||
@issue_statuses = IssueStatus.where(:id => ids).to_a.sort
|
||||
end
|
||||
|
||||
def disabled_core_fields
|
||||
@@ -92,7 +92,7 @@ class Tracker < ActiveRecord::Base
|
||||
# Returns the fields that are disabled for all the given trackers
|
||||
def self.disabled_core_fields(trackers)
|
||||
if trackers.present?
|
||||
trackers.uniq.map(&:disabled_core_fields).reduce(:&)
|
||||
trackers.map(&:disabled_core_fields).reduce(:&)
|
||||
else
|
||||
[]
|
||||
end
|
||||
|
||||
@@ -79,8 +79,8 @@ class User < Principal
|
||||
:after_remove => Proc.new {|user, group| group.user_removed(user)}
|
||||
has_many :changesets, :dependent => :nullify
|
||||
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
|
||||
has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'"
|
||||
has_one :api_token, :class_name => 'Token', :conditions => "action='api'"
|
||||
has_one :rss_token, lambda {where "action='feeds'"}, :class_name => 'Token'
|
||||
has_one :api_token, lambda {where "action='api'"}, :class_name => 'Token'
|
||||
belongs_to :auth_source
|
||||
|
||||
scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") }
|
||||
@@ -105,9 +105,13 @@ class User < Principal
|
||||
validates_length_of :firstname, :lastname, :maximum => 30
|
||||
validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true
|
||||
validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true
|
||||
validates_confirmation_of :password, :allow_nil => true
|
||||
validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
|
||||
validate :validate_password_length
|
||||
validate do
|
||||
if password_confirmation && password != password_confirmation
|
||||
errors.add(:password, :confirmation)
|
||||
end
|
||||
end
|
||||
|
||||
before_create :set_mail_notification
|
||||
before_save :generate_password_if_needed, :update_hashed_password
|
||||
@@ -151,6 +155,15 @@ class User < Principal
|
||||
write_attribute(:mail, arg.to_s.strip)
|
||||
end
|
||||
|
||||
def self.find_or_initialize_by_identity_url(url)
|
||||
user = where(:identity_url => url).first
|
||||
unless user
|
||||
user = User.new
|
||||
user.identity_url = url
|
||||
end
|
||||
user
|
||||
end
|
||||
|
||||
def identity_url=(url)
|
||||
if url.blank?
|
||||
write_attribute(:identity_url, '')
|
||||
@@ -496,10 +509,12 @@ class User < Principal
|
||||
|
||||
hash = Hash.new([])
|
||||
|
||||
members = Member.joins(:project).
|
||||
group_class = anonymous? ? GroupAnonymous : GroupNonMember
|
||||
members = Member.joins(:project, :principal).
|
||||
where("#{Project.table_name}.status <> 9").
|
||||
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)).
|
||||
preload(:project, :roles)
|
||||
where("#{Member.table_name}.user_id = ? OR (#{Project.table_name}.is_public = ? AND #{Principal.table_name}.type = ?)", self.id, true, group_class.name).
|
||||
preload(:project, :roles).
|
||||
to_a
|
||||
|
||||
members.reject! {|member| member.user_id != id && project_ids.include?(member.project_id)}
|
||||
members.each do |member|
|
||||
@@ -558,6 +573,8 @@ class User < Principal
|
||||
# Authorize if user is authorized on every element of the array
|
||||
context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&)
|
||||
end
|
||||
elsif context
|
||||
raise ArgumentError.new("#allowed_to? context argument must be a Project, an Array of projects or nil")
|
||||
elsif options[:global]
|
||||
# Admin users are always authorized
|
||||
return true if admin?
|
||||
@@ -710,17 +727,17 @@ class User < Principal
|
||||
return if self.id.nil?
|
||||
|
||||
substitute = User.anonymous
|
||||
Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
Attachment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
Comment.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
Issue.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
Issue.where(['assigned_to_id = ?', id]).update_all('assigned_to_id = NULL')
|
||||
Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
|
||||
Journal.where(['user_id = ?', id]).update_all(['user_id = ?', substitute.id])
|
||||
JournalDetail.
|
||||
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s]).
|
||||
update_all(['old_value = ?', substitute.id.to_s])
|
||||
JournalDetail.
|
||||
where(["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s]).
|
||||
update_all(['value = ?', substitute.id.to_s])
|
||||
update_all(['value = ?', substitute.id.to_s])
|
||||
Message.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
News.where(['author_id = ?', id]).update_all(['author_id = ?', substitute.id])
|
||||
# Remove private queries and keep public ones
|
||||
|
||||
@@ -33,11 +33,14 @@ class Version < ActiveRecord::Base
|
||||
validates :effective_date, :date => true
|
||||
validates_inclusion_of :status, :in => VERSION_STATUSES
|
||||
validates_inclusion_of :sharing, :in => VERSION_SHARINGS
|
||||
attr_protected :id
|
||||
|
||||
scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)}
|
||||
scope :open, lambda { where(:status => 'open') }
|
||||
scope :visible, lambda {|*args|
|
||||
includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues))
|
||||
joins(:project).
|
||||
references(:project).
|
||||
where(Project.allowed_to_condition(args.first || User.current, :view_issues))
|
||||
}
|
||||
|
||||
safe_attributes 'name',
|
||||
@@ -230,11 +233,6 @@ class Version < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# Returns true if the version is shared, otherwise false
|
||||
def shared?
|
||||
sharing != 'none'
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def load_issue_counts
|
||||
|
||||
@@ -22,6 +22,7 @@ class Watcher < ActiveRecord::Base
|
||||
validates_presence_of :user
|
||||
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id]
|
||||
validate :validate_user
|
||||
attr_protected :id
|
||||
|
||||
# Returns true if at least one object among objects is watched by user
|
||||
def self.any_watched?(objects, user)
|
||||
|
||||
@@ -18,13 +18,14 @@
|
||||
class Wiki < ActiveRecord::Base
|
||||
include Redmine::SafeAttributes
|
||||
belongs_to :project
|
||||
has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
|
||||
has_many :pages, lambda {order('title')}, :class_name => 'WikiPage', :dependent => :destroy
|
||||
has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
|
||||
|
||||
acts_as_watchable
|
||||
|
||||
validates_presence_of :start_page
|
||||
validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/
|
||||
attr_protected :id
|
||||
|
||||
safe_attributes 'start_page'
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ class WikiContent < ActiveRecord::Base
|
||||
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
|
||||
validates_presence_of :text
|
||||
validates_length_of :comments, :maximum => 255, :allow_nil => true
|
||||
attr_protected :id
|
||||
|
||||
acts_as_versioned
|
||||
|
||||
@@ -68,13 +69,13 @@ class WikiContent < ActiveRecord::Base
|
||||
:timestamp => "#{WikiContent.versioned_table_name}.updated_on",
|
||||
:author_key => "#{WikiContent.versioned_table_name}.author_id",
|
||||
:permission => :view_wiki_edits,
|
||||
:find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
|
||||
"#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
|
||||
"#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
|
||||
"#{WikiContent.versioned_table_name}.id",
|
||||
:joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
|
||||
"LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
|
||||
"LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"}
|
||||
:scope => select("#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " +
|
||||
"#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " +
|
||||
"#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " +
|
||||
"#{WikiContent.versioned_table_name}.id").
|
||||
joins("LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " +
|
||||
"LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " +
|
||||
"LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id")
|
||||
|
||||
after_destroy :page_update_after_destroy
|
||||
|
||||
@@ -104,7 +105,7 @@ class WikiContent < ActiveRecord::Base
|
||||
# uncompressed data
|
||||
data
|
||||
end
|
||||
str.force_encoding("UTF-8") if str.respond_to?(:force_encoding)
|
||||
str.force_encoding("UTF-8")
|
||||
str
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,7 +33,7 @@ class WikiPage < ActiveRecord::Base
|
||||
:url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}}
|
||||
|
||||
acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"],
|
||||
:include => [{:wiki => :project}, :content],
|
||||
:scope => preload(:wiki => :project).joins(:content, {:wiki => :project}),
|
||||
:permission => :view_wiki_pages,
|
||||
:project_key => "#{Wiki.table_name}.project_id"
|
||||
|
||||
@@ -43,6 +43,7 @@ class WikiPage < ActiveRecord::Base
|
||||
validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/
|
||||
validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
|
||||
validates_associated :content
|
||||
attr_protected :id
|
||||
|
||||
validate :validate_parent_title
|
||||
before_destroy :remove_redirects
|
||||
@@ -180,12 +181,10 @@ class WikiPage < ActiveRecord::Base
|
||||
def save_with_content(content)
|
||||
ret = nil
|
||||
transaction do
|
||||
self.content = content
|
||||
if new_record?
|
||||
# Rails automatically saves associated content
|
||||
ret = save
|
||||
else
|
||||
ret = save && (content.text_changed? ? content.save : true)
|
||||
ret = save
|
||||
if content.text_changed?
|
||||
self.content = content
|
||||
ret = ret && content.changed?
|
||||
end
|
||||
raise ActiveRecord::Rollback unless ret
|
||||
end
|
||||
|
||||
@@ -20,4 +20,5 @@ class WikiRedirect < ActiveRecord::Base
|
||||
|
||||
validates_presence_of :title, :redirects_to
|
||||
validates_length_of :title, :redirects_to, :maximum => 255
|
||||
attr_protected :id
|
||||
end
|
||||
|
||||
@@ -24,6 +24,7 @@ class WorkflowRule < ActiveRecord::Base
|
||||
belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
|
||||
|
||||
validates_presence_of :role, :tracker, :old_status
|
||||
attr_protected :id
|
||||
|
||||
# Copies workflows from source to targets
|
||||
def self.copy(source_tracker, source_role, target_trackers, target_roles)
|
||||
@@ -34,7 +35,7 @@ class WorkflowRule < ActiveRecord::Base
|
||||
target_trackers = [target_trackers].flatten.compact
|
||||
target_roles = [target_roles].flatten.compact
|
||||
|
||||
target_trackers = Tracker.sorted.all if target_trackers.empty?
|
||||
target_trackers = Tracker.sorted.to_a if target_trackers.empty?
|
||||
target_roles = Role.all if target_roles.empty?
|
||||
|
||||
target_trackers.each do |target_tracker|
|
||||
|
||||
@@ -40,7 +40,7 @@ class WorkflowTransition < WorkflowRule
|
||||
roles = Array.wrap roles
|
||||
|
||||
transaction do
|
||||
records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).all
|
||||
records = WorkflowTransition.where(:tracker_id => trackers.map(&:id), :role_id => roles.map(&:id)).to_a
|
||||
|
||||
transitions.each do |old_status_id, transitions_by_new_status|
|
||||
transitions_by_new_status.each do |new_status_id, transition_by_rule|
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
<% end -%>
|
||||
</ul>
|
||||
<div class="tabs-buttons" style="display:none;">
|
||||
<button class="tab-left" type="button" onclick="moveTabLeft(this);"></button>
|
||||
<button class="tab-right" type="button" onclick="moveTabRight(this);"></button>
|
||||
<button class="tab-left" onclick="moveTabLeft(this); return false;"></button>
|
||||
<button class="tab-right" onclick="moveTabRight(this); return false;"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% roles = Role.find_all_givable %>
|
||||
<% projects = Project.active.all %>
|
||||
<% projects = Project.active.to_a %>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<% if @group.memberships.any? %>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= error_messages_for 'member' %>
|
||||
<% roles = Role.find_all_givable
|
||||
members = @project.member_principals.includes(:member_roles, :roles, :principal).all.sort %>
|
||||
members = @project.member_principals.includes(:member_roles, :roles, :principal).to_a.sort %>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<% if members.any? %>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<% elsif params[:issue_id] %>
|
||||
<%= hidden_field_tag 'issue_id', params[:issue_id] %>
|
||||
<% else %>
|
||||
<p><%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).all, :selected => @time_entry.project, :include_blank => true) %></p>
|
||||
<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>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% roles = Role.find_all_givable %>
|
||||
<% projects = Project.active.all %>
|
||||
<% projects = Project.active.to_a %>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<% if @user.memberships.any? %>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<%= fp.select :parent_id,
|
||||
content_tag('option', '', :value => '') +
|
||||
wiki_page_options_for_select(
|
||||
@wiki.pages.includes(:parent).all -
|
||||
@wiki.pages.includes(:parent).to_a -
|
||||
@page.self_and_descendants, @page.parent) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user