v3.1.0 merged

This commit is contained in:
Kolan Sh 2012-04-05 13:22:02 +04:00
commit e5de5f43cc
116 changed files with 1015 additions and 177 deletions

2
.gitignore vendored
View File

@ -29,3 +29,5 @@ doc/app
/Gemfile.lock /Gemfile.lock
/Gemfile.local /Gemfile.local
/.rvmrc* /.rvmrc*
/*.iml
/.idea

View File

@ -13,6 +13,7 @@ gem "acts-as-taggable-on", "= 2.1.0"
gem "fastercsv", "~> 1.5.0", :platforms => [:ruby_18, :jruby, :mingw_18] gem "fastercsv", "~> 1.5.0", :platforms => [:ruby_18, :jruby, :mingw_18]
# need for automatic encoding detection in diff,annotate and cat # need for automatic encoding detection in diff,annotate and cat
gem "chardet", ">= 0.9.0" gem "chardet", ">= 0.9.0"
gem "tzinfo", "~> 0.3.31" # Fixes #903. Not required for Rails >= 3.2
group :test do group :test do
gem 'shoulda', '~> 2.10.3' gem 'shoulda', '~> 2.10.3'
@ -59,7 +60,7 @@ platforms :mri, :mingw do
end end
group :postgres do group :postgres do
gem "pg", "~> 0.9.0" gem "pg"
# gem "postgres-pr" # gem "postgres-pr"
end end
end end

View File

@ -33,7 +33,7 @@ class ActivitiesController < ApplicationController
:with_subprojects => @with_subprojects, :with_subprojects => @with_subprojects,
:author => @author) :author => @author)
@activity.scope_select {|t| !params["show_#{t}"].nil?} @activity.scope_select {|t| !params["show_#{t}"].nil?}
@activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? unless params[:set_filter]
events = @activity.events(@date_from, @date_to) events = @activity.events(@date_from, @date_to)

View File

@ -64,7 +64,6 @@ class ApplicationController < ActionController::Base
before_filter :user_setup, :check_if_login_required, :set_localization before_filter :user_setup, :check_if_login_required, :set_localization
filter_parameter_logging :password filter_parameter_logging :password
rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token
# FIXME: This doesn't work with Rails >= 3.0 anymore # FIXME: This doesn't work with Rails >= 3.0 anymore
# Possible workaround: https://github.com/rails/rails/issues/671#issuecomment-1780159 # Possible workaround: https://github.com/rails/rails/issues/671#issuecomment-1780159
rescue_from ActionController::RoutingError, :with => proc{render_404} rescue_from ActionController::RoutingError, :with => proc{render_404}
@ -336,13 +335,6 @@ class ApplicationController < ActionController::Base
request.xhr? ? false : 'base' request.xhr? ? false : 'base'
end end
def invalid_authenticity_token
if api_request?
logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)."
end
render_error "Invalid form authenticity token."
end
def render_feed(items, options={}) def render_feed(items, options={})
@items = items || [] @items = items || []
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }

View File

@ -21,7 +21,10 @@ class CommentsController < ApplicationController
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create def create
@comment = Comment.new(params[:comment]) raise Unauthorized unless @news.commentable?
@comment = Comment.new
@comment.safe_attributes = params[:comment]
@comment.author = User.current @comment.author = User.current
if @news.comments << @comment if @news.comments << @comment
flash[:notice] = l(:label_comment_added) flash[:notice] = l(:label_comment_added)

View File

@ -43,7 +43,8 @@ class DocumentsController < ApplicationController
end end
def new def new
@document = @project.documents.build(params[:document]) @document = @project.documents.build
@document.safe_attributes = params[:document]
if request.post? if request.post?
if User.current.allowed_to?(:add_document_watchers, @project) && params[:document]['watcher_user_ids'].present? if User.current.allowed_to?(:add_document_watchers, @project) && params[:document]['watcher_user_ids'].present?
@document.watcher_user_ids = params[:document]['watcher_user_ids'] @document.watcher_user_ids = params[:document]['watcher_user_ids']

View File

@ -23,7 +23,8 @@ class IssueCategoriesController < ApplicationController
verify :method => :post, :only => :destroy verify :method => :post, :only => :destroy
def new def new
@category = @project.issue_categories.build(params[:category]) @category = @project.issue_categories.build
@category.safe_attributes = params[:category]
if request.post? if request.post?
if @category.save if @category.save
respond_to do |format| respond_to do |format|
@ -50,7 +51,8 @@ class IssueCategoriesController < ApplicationController
end end
def edit def edit
if request.post? and @category.update_attributes(params[:category]) @category.safe_attributes = params[:category]
if request.post? and @category.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
end end

View File

@ -21,17 +21,19 @@ class MembersController < ApplicationController
def new def new
members = [] members = []
if params[:member] && request.post? if params[:member]
attrs = params[:member].dup if params[:member][:user_ids]
if (user_ids = attrs.delete(:user_ids)) attrs = params[:member].dup
user_ids = attrs.delete(:user_ids)
user_ids.each do |user_id| user_ids.each do |user_id|
members << Member.new(attrs.merge(:user_id => user_id)) members << Member.new(:role_ids => params[:member][:role_ids], :user_id => user_id)
end end
else else
members << Member.new(attrs) members << Member.new(:role_ids => params[:member][:role_ids], :user_id => params[:member][:user_id])
end end
@project.members << members @project.members << members
end end
respond_to do |format| respond_to do |format|
if members.present? && members.all? {|m| m.valid? } if members.present? && members.all? {|m| m.valid? }

View File

@ -48,26 +48,26 @@ class MessagesController < ApplicationController
# Create a new topic # Create a new topic
def new def new
@message = Message.new(params[:message]) @message = Message.new
@message.author = User.current @message.author = User.current
@message.board = @board @message.board = @board
if params[:message] && User.current.allowed_to?(:edit_messages, @project) @message.safe_attributes = params[:message]
@message.locked = params[:message]['locked'] if request.post?
@message.sticky = params[:message]['sticky'] if @message.save
end call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
if request.post? && @message.save attachments = Attachment.attach_files(@message, params[:attachments])
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) render_attachment_warning_if_needed(@message)
attachments = Attachment.attach_files(@message, params[:attachments]) redirect_to :action => 'show', :id => @message
render_attachment_warning_if_needed(@message) end
redirect_to :action => 'show', :id => @message
end end
end end
# Reply to a topic # Reply to a topic
def reply def reply
@reply = Message.new(params[:reply]) @reply = Message.new
@reply.author = User.current @reply.author = User.current
@reply.board = @board @reply.board = @board
@reply.safe_attributes = params[:reply]
@topic.children << @reply @topic.children << @reply
if !@reply.new_record? if !@reply.new_record?
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
@ -80,11 +80,8 @@ class MessagesController < ApplicationController
# Edit a message # Edit a message
def edit def edit
(render_403; return false) unless @message.editable_by?(User.current) (render_403; return false) unless @message.editable_by?(User.current)
if params[:message] @message.safe_attributes = params[:message]
@message.locked = params[:message]['locked'] if request.post? && @message.save
@message.sticky = params[:message]['sticky']
end
if request.post? && @message.update_attributes(params[:message])
attachments = Attachment.attach_files(@message, params[:attachments]) attachments = Attachment.attach_files(@message, params[:attachments])
render_attachment_warning_if_needed(@message) render_attachment_warning_if_needed(@message)
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)

View File

@ -59,14 +59,12 @@ class NewsController < ApplicationController
def create def create
@news = News.new(:project => @project, :author => User.current) @news = News.new(:project => @project, :author => User.current)
if request.post? @news.safe_attributes = params[:news]
@news.attributes = params[:news] if @news.save
if @news.save flash[:notice] = l(:notice_successful_create)
flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'news', :action => 'index', :project_id => @project
redirect_to :controller => 'news', :action => 'index', :project_id => @project else
else render :action => 'new'
render :action => 'new'
end
end end
end end
@ -74,7 +72,8 @@ class NewsController < ApplicationController
end end
def update def update
if request.put? and @news.update_attributes(params[:news]) @news.safe_attributes = params[:news]
if @news.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @news redirect_to :action => 'show', :id => @news
else else

View File

@ -59,7 +59,8 @@ class ProjectsController < ApplicationController
def new def new
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
@trackers = Tracker.all @trackers = Tracker.all
@project = Project.new(params[:project]) @project = Project.new
@project.safe_attributes = params[:project]
end end
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }

View File

@ -97,7 +97,7 @@ class TimelogController < ApplicationController
def new def new
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
@time_entry.attributes = params[:time_entry] @time_entry.safe_attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
render :action => 'edit' render :action => 'edit'
@ -106,7 +106,7 @@ class TimelogController < ApplicationController
verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed }
def create def create
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today)
@time_entry.attributes = params[:time_entry] @time_entry.safe_attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
@ -127,14 +127,14 @@ class TimelogController < ApplicationController
end end
def edit def edit
@time_entry.attributes = params[:time_entry] @time_entry.safe_attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
end end
verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed }
def update def update
@time_entry.attributes = params[:time_entry] @time_entry.safe_attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })

View File

@ -56,7 +56,7 @@ class VersionsController < ApplicationController
if params[:version] if params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
@version.attributes = attributes @version.safe_attributes = attributes
end end
end end
@ -66,7 +66,7 @@ class VersionsController < ApplicationController
if params[:version] if params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing'])
@version.attributes = attributes @version.safe_attributes = attributes
end end
if request.post? if request.post?
@ -101,7 +101,8 @@ class VersionsController < ApplicationController
if request.put? && params[:version] if request.put? && params[:version]
attributes = params[:version].dup attributes = params[:version].dup
attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing'])
if @version.update_attributes(attributes) @version.safe_attributes = attributes
if @version.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
else else

View File

@ -19,7 +19,7 @@ class WikisController < ApplicationController
# Create or update a project's wiki # Create or update a project's wiki
def edit def edit
@wiki = @project.wiki || Wiki.new(:project => @project) @wiki = @project.wiki || Wiki.new(:project => @project)
@wiki.attributes = params[:wiki] @wiki.safe_attributes = params[:wiki]
@wiki.save if request.post? @wiki.save if request.post?
render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'} render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'}
end end

View File

@ -502,7 +502,7 @@ module ApplicationHelper
@parsed_headings = [] @parsed_headings = []
text = parse_non_pre_blocks(text) do |text| text = parse_non_pre_blocks(text) do |text|
[:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings, :parse_relative_urls].each do |method_name|
send method_name, text, project, obj, attr, only_path, options send method_name, text, project, obj, attr, only_path, options
end end
end end
@ -543,6 +543,41 @@ module ApplicationHelper
parsed parsed
end end
RELATIVE_LINK_RE = %r{
<a
(?:
(\shref=
(?: # the href and link
(?:'(\/[^>]+?)')|
(?:"(\/[^>]+?)")
)
)|
[^>]
)*
>
[^<]*?<\/a> # content and closing link tag.
}x unless const_defined?(:RELATIVE_LINK_RE)
def parse_relative_urls(text, project, obj, attr, only_path, options)
return if only_path
text.gsub!(RELATIVE_LINK_RE) do |m|
href, relative_url = $1, $2 || $3
next m unless href.present?
if defined?(request) && request.present?
# we have a request!
protocol, host_with_port = request.protocol, request.host_with_port
elsif @controller
# use the same methods as url_for in the Mailer
url_opts = @controller.class.default_url_options
next m unless url_opts && url_opts[:protocol] && url_opts[:host]
protocol, host_with_port = "#{url_opts[:protocol]}://", url_opts[:host]
else
next m
end
m.sub href, " href=\"#{protocol}#{host_with_port}#{relative_url}\""
end
end
def parse_inline_attachments(text, project, obj, attr, only_path, options) def parse_inline_attachments(text, project, obj, attr, only_path, options)
# when using an image link, try to use an attachment, if possible # when using an image link, try to use an attachment, if possible
if options[:attachments] || (obj && obj.respond_to?(:attachments)) if options[:attachments] || (obj && obj.respond_to?(:attachments))
@ -816,7 +851,7 @@ module ApplicationHelper
def back_url_hidden_field_tag def back_url_hidden_field_tag
back_url = params[:back_url] || request.env['HTTP_REFERER'] back_url = params[:back_url] || request.env['HTTP_REFERER']
back_url = CGI.unescape(back_url.to_s) back_url = CGI.unescape(back_url.to_s)
hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? hidden_field_tag('back_url', CGI.escape(back_url), :id => nil) unless back_url.blank?
end end
def check_all_links(form_name) def check_all_links(form_name)
@ -850,7 +885,7 @@ module ApplicationHelper
def context_menu(url) def context_menu(url)
unless @context_menu_included unless @context_menu_included
content_for :header_tags do content_for :header_tags do
javascript_include_tag('context_menu') + javascript_include_tag('context_menu.jquery') +
stylesheet_link_tag('context_menu') stylesheet_link_tag('context_menu')
end end
if l(:direction) == 'rtl' if l(:direction) == 'rtl'
@ -860,7 +895,7 @@ module ApplicationHelper
end end
@context_menu_included = true @context_menu_included = true
end end
javascript_tag "new ContextMenu('#{ url_for(url) }')" javascript_tag "jQuery(document).ContextMenu('#{ url_for(url) }')"
end end
def context_menu_link(name, url, options={}) def context_menu_link(name, url, options={})

View File

@ -79,6 +79,22 @@ module IssuesHelper
s s
end end
def render_parents_and_subtree(issue)
return if issue.leaf? && !issue.parent
s = '<form><table id="issue_tree" class="list">'
issue_list(issue.self_and_ancestors.sort_by(&:lft) + issue.descendants.sort_by(&:lft)) do |el, level|
s << content_tag('tr',
content_tag('td', check_box_tag("ids[]", el.id, false, :id => nil), :class => 'checkbox') +
content_tag('td', link_to_issue(el, :truncate => 60), :class => 'subject') +
content_tag('td', h(el.status)) +
content_tag('td', link_to_user(el.assigned_to)) +
content_tag('td', progress_bar(el.done_ratio, :width => '80px')),
:class => "issue issue-#{el.id} #{"self" if el == issue} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
end
s << '</table></form>'
s
end
def render_custom_fields_rows(issue) def render_custom_fields_rows(issue)
return if issue.custom_field_values.empty? return if issue.custom_field_values.empty?
ordered_values = [] ordered_values = []

View File

@ -13,8 +13,11 @@
#++ #++
class Comment < ActiveRecord::Base class Comment < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :commented, :polymorphic => true, :counter_cache => true belongs_to :commented, :polymorphic => true, :counter_cache => true
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :commented, :author, :comments validates_presence_of :commented, :author, :comments
safe_attributes 'comments'
end end

View File

@ -13,6 +13,7 @@
#++ #++
class Document < ActiveRecord::Base class Document < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id"
acts_as_attachable :delete_permission => :manage_documents acts_as_attachable :delete_permission => :manage_documents
@ -32,6 +33,8 @@ class Document < ActiveRecord::Base
named_scope :visible, lambda {|*args| { :include => :project, named_scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.first || User.current, :view_documents) } } :conditions => Project.allowed_to_condition(args.first || User.current, :view_documents) } }
safe_attributes 'category_id', 'title', 'description'
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_documents, project) !user.nil? && user.allowed_to?(:view_documents, project)
end end

View File

@ -48,4 +48,9 @@ class Group < Principal
:conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy) :conditions => ["#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids]).each(&:destroy)
end end
end end
def self.human_attribute_name(attribute_name)
attribute_name = "name" if attribute_name == "lastname"
super(attribute_name)
end
end end

View File

@ -707,6 +707,15 @@ class Issue < ActiveRecord::Base
projects projects
end end
# Overrides Redmine::Acts::Journalized::Permissions
#
# The default assumption is that journals have the same permissions
# as the journaled object, issue notes have separate permissions though
def journal_editable_by?(journal, user)
return true if journal.author == user && user.allowed_to?(:edit_own_issue_notes, project)
user.allowed_to? :edit_issue_notes, project
end
private private
def update_nested_set_attributes def update_nested_set_attributes

View File

@ -13,6 +13,7 @@
#++ #++
class IssueCategory < ActiveRecord::Base class IssueCategory < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
has_many :issues, :foreign_key => 'category_id', :dependent => :nullify has_many :issues, :foreign_key => 'category_id', :dependent => :nullify
@ -21,6 +22,8 @@ class IssueCategory < ActiveRecord::Base
validates_uniqueness_of :name, :scope => [:project_id] validates_uniqueness_of :name, :scope => [:project_id]
validates_length_of :name, :maximum => 30 validates_length_of :name, :maximum => 30
safe_attributes 'name', 'assigned_to_id'
alias :destroy_without_reassign :destroy alias :destroy_without_reassign :destroy
# Destroy the category # Destroy the category

View File

@ -76,7 +76,7 @@ class Journal < ActiveRecord::Base
end end
def editable_by?(user) def editable_by?(user)
journaled.journal_editable_by?(user) journaled.journal_editable_by?(self, user)
end end
def details def details

View File

@ -13,6 +13,7 @@
#++ #++
class Message < ActiveRecord::Base class Message < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :board belongs_to :board
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
@ -49,6 +50,12 @@ class Message < ActiveRecord::Base
named_scope :visible, lambda {|*args| { :include => {:board => :project}, named_scope :visible, lambda {|*args| { :include => {:board => :project},
:conditions => Project.allowed_to_condition(args.first || User.current, :view_messages) } } :conditions => Project.allowed_to_condition(args.first || User.current, :view_messages) } }
safe_attributes 'subject', 'content'
safe_attributes 'locked', 'sticky',
:if => lambda {|message, user|
user.allowed_to?(:edit_messages, message.project)
}
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_messages, project) !user.nil? && user.allowed_to?(:view_messages, project)
end end

View File

@ -13,6 +13,7 @@
#++ #++
class News < ActiveRecord::Base class News < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
@ -21,7 +22,8 @@ class News < ActiveRecord::Base
validates_length_of :title, :maximum => 60 validates_length_of :title, :maximum => 60
validates_length_of :summary, :maximum => 255 validates_length_of :summary, :maximum => 255
acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.journaled_id} } acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.journaled_id} },
:event_description => :description
acts_as_searchable :columns => ["#{table_name}.title", "#{table_name}.summary", "#{table_name}.description"], :include => :project acts_as_searchable :columns => ["#{table_name}.title", "#{table_name}.summary", "#{table_name}.description"], :include => :project
acts_as_watchable acts_as_watchable
@ -32,10 +34,17 @@ class News < ActiveRecord::Base
:conditions => Project.allowed_to_condition(args.first || User.current, :view_news) :conditions => Project.allowed_to_condition(args.first || User.current, :view_news)
}} }}
safe_attributes 'title', 'summary', 'description'
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_news, project) !user.nil? && user.allowed_to?(:view_news, project)
end end
# Returns true if the news can be commented by user
def commentable?(user=User.current)
user.allowed_to?(:comment_news, project)
end
# returns latest news for projects visible by user # returns latest news for projects visible by user
def self.latest(user = User.current, count = 5) def self.latest(user = User.current, count = 5)
find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/bazaar_adapter' require_dependency 'redmine/scm/adapters/bazaar_adapter'
class Repository::Bazaar < Repository class Repository::Bazaar < Repository
attr_protected :root_url attr_protected :root_url

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/cvs_adapter' require_dependency 'redmine/scm/adapters/cvs_adapter'
require 'digest/sha1' require 'digest/sha1'
class Repository::Cvs < Repository class Repository::Cvs < Repository

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/darcs_adapter' require_dependency 'redmine/scm/adapters/darcs_adapter'
class Repository::Darcs < Repository class Repository::Darcs < Repository
validates_presence_of :url, :log_encoding validates_presence_of :url, :log_encoding

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/filesystem_adapter' require_dependency 'redmine/scm/adapters/filesystem_adapter'
class Repository::Filesystem < Repository class Repository::Filesystem < Repository
attr_protected :root_url attr_protected :root_url

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/git_adapter' require_dependency 'redmine/scm/adapters/git_adapter'
class Repository::Git < Repository class Repository::Git < Repository
attr_protected :root_url attr_protected :root_url

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/mercurial_adapter' require_dependency 'redmine/scm/adapters/mercurial_adapter'
class Repository::Mercurial < Repository class Repository::Mercurial < Repository
# sort changesets by revision number # sort changesets by revision number

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/subversion_adapter' require_dependency 'redmine/scm/adapters/subversion_adapter'
class Repository::Subversion < Repository class Repository::Subversion < Repository
attr_protected :root_url attr_protected :root_url

View File

@ -13,6 +13,7 @@
#++ #++
class TimeEntry < ActiveRecord::Base class TimeEntry < ActiveRecord::Base
include Redmine::SafeAttributes
# could have used polymorphic association # could have used polymorphic association
# project association here allows easy loading of time entries at project level with one database trip # project association here allows easy loading of time entries at project level with one database trip
belongs_to :project belongs_to :project
@ -37,6 +38,8 @@ class TimeEntry < ActiveRecord::Base
:conditions => Project.allowed_to_condition(args.first || User.current, :view_time_entries) :conditions => Project.allowed_to_condition(args.first || User.current, :view_time_entries)
}} }}
safe_attributes 'hours', 'comments', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values'
def after_initialize def after_initialize
if new_record? && self.activity.nil? if new_record? && self.activity.nil?
if default_activity = TimeEntryActivity.default if default_activity = TimeEntryActivity.default

View File

@ -64,10 +64,9 @@ class User < Principal
validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
# Login must contain lettres, numbers, underscores only # Login must contain lettres, numbers, underscores only
validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
validates_length_of :login, :maximum => 30 validates_length_of :login, :firstname, :lastname, :maximum => 255
validates_length_of :firstname, :lastname, :maximum => 30
validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i, :allow_nil => true
validates_length_of :mail, :maximum => 60, :allow_nil => true validates_length_of :mail, :maximum => 255, :allow_nil => true
validates_confirmation_of :password, :allow_nil => true validates_confirmation_of :password, :allow_nil => true
validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
validates_inclusion_of :status, :in => [STATUS_ANONYMOUS, STATUS_ACTIVE, STATUS_REGISTERED, STATUS_LOCKED] validates_inclusion_of :status, :in => [STATUS_ANONYMOUS, STATUS_ACTIVE, STATUS_REGISTERED, STATUS_LOCKED]

View File

@ -16,7 +16,7 @@ class UserPreference < ActiveRecord::Base
belongs_to :user belongs_to :user
serialize :others serialize :others
attr_protected :others attr_protected :others, :user_id
def initialize(attributes = nil) def initialize(attributes = nil)
super super

View File

@ -13,6 +13,7 @@
#++ #++
class Version < ActiveRecord::Base class Version < ActiveRecord::Base
include Redmine::SafeAttributes
after_update :update_issues_from_sharing_change after_update :update_issues_from_sharing_change
belongs_to :project belongs_to :project
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify
@ -34,6 +35,15 @@ class Version < ActiveRecord::Base
named_scope :visible, lambda {|*args| { :include => :project, named_scope :visible, lambda {|*args| { :include => :project,
:conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } } :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } }
safe_attributes 'name',
'description',
'effective_date',
'due_date',
'wiki_page_title',
'status',
'sharing',
'custom_field_values'
# Returns true if +user+ or current user is allowed to view the version # Returns true if +user+ or current user is allowed to view the version
def visible?(user=User.current) def visible?(user=User.current)
user.allowed_to?(:view_issues, self.project) user.allowed_to?(:view_issues, self.project)

View File

@ -13,6 +13,7 @@
#++ #++
class Wiki < ActiveRecord::Base class Wiki < ActiveRecord::Base
include Redmine::SafeAttributes
belongs_to :project belongs_to :project
has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title' has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title'
has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all
@ -22,6 +23,8 @@ class Wiki < ActiveRecord::Base
validates_presence_of :start_page validates_presence_of :start_page
validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/ validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/
safe_attributes 'start_page'
def visible?(user=User.current) def visible?(user=User.current)
!user.nil? && user.allowed_to?(:view_wiki_pages, project) !user.nil? && user.allowed_to?(:view_wiki_pages, project)
end end

View File

@ -1,10 +1,11 @@
<div id="nav-login-content"> <div id="nav-login-content">
<% form_tag({:controller => "account", :action=> "login"}) do %> <% form_tag({:controller => "account", :action=> "login"}) do %>
<%= hidden_field_tag('back_url', CGI.escape(request.url)) %> <%= hidden_field_tag 'back_url', CGI.escape(request.url), :id => nil %>
<table> <table>
<tr> <tr>
<td><label for="username-pulldown"><%= l(:field_login) %></label></td> <td><label for="username-pulldown"><%= l(:field_login) %></label></td>
<td><label for="password-pulldown"><%= l(:field_password) %></label></td> <td><label for="password-pulldown"><%= l(:field_password) %></label></td>
<td></td>
</tr> </tr>
<tr> <tr>
<td><%= text_field_tag 'username', nil, :tabindex => '1', :id => 'username-pulldown' %></td> <td><%= text_field_tag 'username', nil, :tabindex => '1', :id => 'username-pulldown' %></td>

View File

@ -42,6 +42,7 @@
<% content_for :sidebar do %> <% content_for :sidebar do %>
<% form_tag({}, :method => :get) do %> <% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3> <h3><%= l(:label_activity) %></h3>
<%= hidden_field_tag "set_filter", 1, :id => nil %>
<p><% @activity.event_types.each do |t| %> <p><% @activity.event_types.each do |t| %>
<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> <%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
<label for="show_<%=t%>"><%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%></label> <label for="show_<%=t%>"><%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%></label>

View File

@ -72,7 +72,7 @@ t_height = g_height + headers_height
<p class="warning"><%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %></p> <p class="warning"><%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %></p>
<% end %> <% end %>
<table width="100%" style="border:0; border-collapse: collapse;"> <table style="width:100%; border:0; border-collapse: collapse;">
<tr> <tr>
<td style="width:<%= subject_width %>px; padding:0px;"> <td style="width:<%= subject_width %>px; padding:0px;">
@ -98,7 +98,7 @@ month_f = @gantt.date_from
left = 0 left = 0
height = (show_weeks ? header_heigth : header_heigth + g_height) height = (show_weeks ? header_heigth : header_heigth + g_height)
@gantt.months.times do @gantt.months.times do
width = ((month_f >> 1) - month_f) * zoom - 1 width = (((month_f >> 1) - month_f) * zoom - 1).to_i
%> %>
<div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr"> <div style="left:<%= left %>px;width:<%= width %>px;height:<%= height %>px;" class="gantt_hdr">
<%= link_to h("#{month_f.year}-#{month_f.month}"), @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%> <%= link_to h("#{month_f.year}-#{month_f.month}"), @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
@ -176,7 +176,7 @@ if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
</tr> </tr>
</table> </table>
<table width="100%"> <table style="width:100%">
<tr> <tr>
<td align="left"><%= link_to_content_update('&#171; ' + l(:label_previous), params.merge(@gantt.params_previous)) %></td> <td align="left"><%= link_to_content_update('&#171; ' + l(:label_previous), params.merge(@gantt.params_previous)) %></td>
<td align="right"><%= link_to_content_update(l(:label_next) + ' &#187;', params.merge(@gantt.params_next)) %></td> <td align="right"><%= link_to_content_update(l(:label_next) + ' &#187;', params.merge(@gantt.params_next)) %></td>

View File

@ -12,7 +12,7 @@
<% html_title "Wiki Syntax Quick Reference" %> <% html_title "Wiki Syntax Quick Reference" %>
<h1>Wiki Syntax Quick Reference</h1> <h1>Wiki Syntax Quick Reference</h1>
<table width="100%"> <table style="width:100%">
<tr><th colspan="3">Font Styles</th></tr> <tr><th colspan="3">Font Styles</th></tr>
<tr><th><img src="../images/jstoolbar/bt_strong.png" style="border: 1px solid #bbb;" alt="Strong" /></th><td width="50%">*Strong*</td><td width="50%"><strong>Strong</strong></td></tr> <tr><th><img src="../images/jstoolbar/bt_strong.png" style="border: 1px solid #bbb;" alt="Strong" /></th><td width="50%">*Strong*</td><td width="50%"><strong>Strong</strong></td></tr>
<tr><th><img src="../images/jstoolbar/bt_em.png" style="border: 1px solid #bbb;" alt="Italic" /></th><td>_Italic_</td><td><em>Italic</em></td></tr> <tr><th><img src="../images/jstoolbar/bt_em.png" style="border: 1px solid #bbb;" alt="Italic" /></th><td>_Italic_</td><td><em>Italic</em></td></tr>

View File

@ -1,5 +1,5 @@
<% form_tag({}) do -%> <% form_tag({}) do -%>
<%= hidden_field_tag 'back_url', url_for(params) %> <%= hidden_field_tag 'back_url', url_for(params), :id => nil %>
<div class="autoscroll"> <div class="autoscroll">
<table class="list issues"> <table class="list issues">
<thead><tr> <thead><tr>

View File

@ -0,0 +1,11 @@
<% if !@issue.leaf? || @issue.parent || User.current.allowed_to?(:manage_subtasks, @project) %>
<hr />
<p>
<strong><%= l(:label_issue_hierarchy) %></strong>
<% if User.current.allowed_to?(:manage_subtasks, @project) %>
(<%= link_to(l(:label_subtask_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) %>)
<% end %>
</p>
<% end %>
<%= render_parents_and_subtree @issue %>

View File

@ -39,12 +39,16 @@
<% if User.current.allowed_to?(:view_time_entries, @project) %> <% if User.current.allowed_to?(:view_time_entries, @project) %>
<th class="spent-time"><%=l(:label_spent_time)%>:</th> <th class="spent-time"><%=l(:label_spent_time)%>:</th>
<td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %></td> <td class="spent-time"><%= @issue.spent_hours > 0 ? (link_to l_hours(@issue.spent_hours), {:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}) : "-" %></td>
<% else %>
<th></th><td></td>
<% end %> <% end %>
</tr> </tr>
<tr> <tr>
<th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td> <th class="fixed-version"><%=l(:field_fixed_version)%>:</th><td class="fixed-version"><%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %></td>
<% if @issue.estimated_hours %> <% if @issue.estimated_hours %>
<th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td> <th class="estimated-hours"><%=l(:field_estimated_hours)%>:</th><td class="estimated-hours"><%= l_hours(@issue.estimated_hours) %></td>
<% else %>
<th></th><td></td>
<% end %> <% end %>
</tr> </tr>
<%= render_custom_fields_rows(@issue) %> <%= render_custom_fields_rows(@issue) %>
@ -74,26 +78,16 @@
<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> <%= render :partial => 'tree_simple' %>
<hr />
<div id="issue_tree">
<p>
<strong><%=l(:label_subtask_plural)%></strong>
(<%= link_to(l(:button_add), {:controller => 'issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>)
</p>
<%= render_descendants_tree(@issue) unless @issue.leaf? %>
</div>
<% end %>
<% if authorize_for('issue_relations', 'new') || @issue.relations.present? %> <% if authorize_for('issue_relations', 'new') || @issue.relations.present? %>
<hr /> <hr />
<div id="relations"> <div id="relations">
<%= render :partial => 'relations' %> <%= render :partial => 'relations' %>
</div> </div>
<hr />
<% end %> <% end %>
<hr />
</div> </div>
<% if @changesets.present? %> <% if @changesets.present? %>
@ -148,9 +142,8 @@
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %>
<%= stylesheet_link_tag 'scm' %> <%= stylesheet_link_tag 'scm' %>
<%= javascript_include_tag 'context_menu' %> <%= javascript_include_tag 'context_menu.jquery' %>
<%= stylesheet_link_tag 'context_menu' %> <%= stylesheet_link_tag 'context_menu' %>
<%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %> <%= stylesheet_link_tag 'context_menu_rtl' if l(:direction) == 'rtl' %>
<% end %> <% end %>
<div id="context-menu" style="display: none;"></div> <%= javascript_tag "jQuery(document).ContextMenu('#{issues_context_menu_path}')" %>
<%= javascript_tag "new ContextMenu('#{issues_context_menu_path}')" %>

View File

@ -74,7 +74,6 @@
</ul> </ul>
</li> </li>
<% end %> <% end %>
<li>
<%= render_menu_node(help_menu_item) %> <%= render_menu_node(help_menu_item) %>
<% unless User.current.logged? %> <% unless User.current.logged? %>
<% if Setting.self_registration? %> <% if Setting.self_registration? %>
@ -98,7 +97,6 @@
</ul> </ul>
</li> </li>
<% end %> <% end %>
</li>
</ul> </ul>
<% end %> <% end %>
</div> </div>

View File

@ -1,13 +1,13 @@
<table style="border-collapse: collapse; border:0;"> <table class="query-columns">
<tr> <tr>
<td style="padding-left:0"> <td style="padding-left:0">
<%= label_tag "available_columns", l(:description_available_columns) %> <%= label_tag "available_columns", l(:description_available_columns) %>
<br \> <br />
<%= select_tag 'available_columns', <%= select_tag 'available_columns',
options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}), options_for_select((query.available_columns - query.columns).collect {|column| [column.caption, column.name]}),
:multiple => true, :size => 10, :style => "width:150px" %> :multiple => true, :size => 10, :style => "width:150px" %>
</td> </td>
<td align="center" valign="middle"> <td class="buttons">
<input type="button" value="&#8594;" <input type="button" value="&#8594;"
onclick="moveOptions(this.form.available_columns, this.form.selected_columns);" /><br /> onclick="moveOptions(this.form.available_columns, this.form.selected_columns);" /><br />
<input type="button" value="&#8592;" <input type="button" value="&#8592;"
@ -15,12 +15,12 @@
</td> </td>
<td> <td>
<%= label_tag "selected_columns", l(:description_selected_columns) %> <%= label_tag "selected_columns", l(:description_selected_columns) %>
<br \> <br />
<%= select_tag 'c[]', <%= select_tag 'c[]',
options_for_select(query.columns.collect {|column| [column.caption, column.name]}), options_for_select(query.columns.collect {|column| [column.caption, column.name]}),
:id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px" %> :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px" %>
</td> </td>
<td align="center" valign="middle"> <td class="buttons">
<input type="button" value="&#8593;" onclick="moveOptionUp(this.form.selected_columns);" /><br /> <input type="button" value="&#8593;" onclick="moveOptionUp(this.form.selected_columns);" /><br />
<input type="button" value="&#8595;" onclick="moveOptionDown(this.form.selected_columns);" /> <input type="button" value="&#8595;" onclick="moveOptionDown(this.form.selected_columns);" />
</td> </td>

View File

@ -100,7 +100,7 @@ Event.observe(document,"dom:loaded", apply_filters_observer);
//]]> //]]>
</script> </script>
<table width="100%"> <table style="width:100%">
<tr> <tr>
<td> <td>
<table> <table>
@ -113,7 +113,7 @@ Event.observe(document,"dom:loaded", apply_filters_observer);
<label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label> <label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label>
</td> </td>
<td style="width:150px;"> <td style="width:150px;">
<%= label_tag "op_#{field}", l(:description_filter), :class => "hidden-for-sighted" %> <%= label_tag "operators_#{field}", l(:description_filter), :class => "hidden-for-sighted" %>
<%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %> <%= select_tag "op[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %>
</td> </td>
<td> <td>

View File

@ -53,17 +53,16 @@
# #
# ==== SMTP server at using TLS (GMail) # ==== SMTP server at using TLS (GMail)
# #
# This requires some additional configuration. See the article at: # This might require some additional configuration. See the guides at:
# http://redmineblog.com/articles/setup-redmine-to-send-email-using-gmail/ # https://www.chiliproject.org/projects/chiliproject/wiki/Email_Delivery#SMTP-server-using-TLS-GMail
# #
# production: # production:
# email_delivery: # email_delivery:
# delivery_method: :smtp # delivery_method: :smtp
# smtp_settings: # smtp_settings:
# tls: true # enable_starttls_auto: true
# address: "smtp.gmail.com" # address: "smtp.gmail.com"
# port: 587 # port: 587
# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps
# authentication: :plain # authentication: :plain
# user_name: "your_email@gmail.com" # user_name: "your_email@gmail.com"
# password: "your_password" # password: "your_password"

View File

@ -997,3 +997,8 @@ bg:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1011,3 +1011,8 @@ bs:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1000,3 +1000,8 @@ ca:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1221,3 +1221,8 @@ cs:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1013,3 +1013,8 @@ da:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -796,6 +796,8 @@ de:
label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt
label_profile: Profil label_profile: Profil
label_subtask_plural: Unteraufgaben label_subtask_plural: Unteraufgaben
label_subtask_add: Unteraufgabe hinzufügen
label_issue_hierarchy: Tickethierarchie
label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts.
label_principal_search: "Nach Benutzer oder Gruppe suchen:" label_principal_search: "Nach Benutzer oder Gruppe suchen:"
label_user_search: "Nach Benutzer suchen:" label_user_search: "Nach Benutzer suchen:"
@ -1014,3 +1016,6 @@ de:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues

View File

@ -997,3 +997,8 @@ el:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1001,3 +1001,8 @@ en-GB:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -309,6 +309,9 @@ en:
field_visible: Visible field_visible: Visible
field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text"
field_custom_filter: Custom LDAP filter field_custom_filter: Custom LDAP filter
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
setting_app_title: Application title setting_app_title: Application title
setting_app_subtitle: Application subtitle setting_app_subtitle: Application subtitle
@ -805,6 +808,8 @@ en:
label_api_access_key_created_on: "API access key created %{value} ago" label_api_access_key_created_on: "API access key created %{value} ago"
label_profile: Profile label_profile: Profile
label_subtask_plural: Subtasks label_subtask_plural: Subtasks
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy
label_project_copy_notifications: Send email notifications during the project copy label_project_copy_notifications: Send email notifications during the project copy
label_principal_search: "Search for user or group:" label_principal_search: "Search for user or group:"
label_user_search: "Search for user:" label_user_search: "Search for user:"

View File

@ -1034,3 +1034,8 @@ es:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1001,3 +1001,8 @@ eu:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1000,3 +1000,8 @@ fa:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1018,3 +1018,8 @@ fi:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1015,3 +1015,8 @@ fr:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1009,3 +1009,8 @@ gl:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1002,3 +1002,8 @@ he:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1004,3 +1004,8 @@ hr:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1016,3 +1016,8 @@
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1005,3 +1005,8 @@ id:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -998,3 +998,8 @@ it:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1019,3 +1019,8 @@ ja:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1049,3 +1049,8 @@ ko:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1057,3 +1057,8 @@ lt:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -992,3 +992,8 @@ lv:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -997,3 +997,8 @@ mk:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -998,3 +998,8 @@ mn:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -979,3 +979,8 @@ nl:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -984,3 +984,8 @@
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1014,3 +1014,8 @@ pl:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1021,3 +1021,8 @@ pt-BR:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1001,3 +1001,8 @@ pt:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -990,3 +990,8 @@ ro:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1110,3 +1110,8 @@ ru:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -992,3 +992,8 @@ sk:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -993,3 +993,8 @@ sl:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -997,3 +997,8 @@ sr-YU:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -998,3 +998,8 @@ sr:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1039,3 +1039,8 @@ sv:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -994,3 +994,8 @@ th:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1016,3 +1016,8 @@ tr:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -993,3 +993,8 @@ uk:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1048,3 +1048,8 @@ vi:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1079,3 +1079,8 @@
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -1011,3 +1011,8 @@ zh:
label_mail_handler_failure: "Failed email submission: %{subject}" label_mail_handler_failure: "Failed email submission: %{subject}"
notice_not_authorized_action: You are not authorized to perform this action. notice_not_authorized_action: You are not authorized to perform this action.
text_mail_handler_confirmation_successful: Your email has been successful added at the following url text_mail_handler_confirmation_successful: Your email has been successful added at the following url
field_issue_summary: Issue summary
field_new_saved_query: New saved query
field_issue_view_all_open: View all open issues
label_subtask_add: Add a subtask
label_issue_hierarchy: Issue hierarchy

View File

@ -0,0 +1,29 @@
#-- encoding: UTF-8
#-- copyright
# ChiliProject is a project management system.
#
# Copyright (C) 2010-2012 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
class UpUserFieldsLengthLimits < ActiveRecord::Migration
def self.up
change_column :users, :login, :string, :limit => nil
change_column :users, :mail, :string, :limit => nil
change_column :users, :firstname, :string, :limit => nil
change_column :users, :lastname, :string, :limit => nil
end
def self.down
change_column :users, :login, :string, :limit => 30
change_column :users, :mail, :string, :limit => 60
change_column :users, :firstname, :string, :limit => 30
change_column :users, :lastname, :string, :limit => 30
end
end

View File

@ -1,5 +1,33 @@
= ChiliProject Changelog = ChiliProject Changelog
== 2012-04-04 v3.1.0
* Bug #739: Relative textile links not converted to full URLs in emails
* Bug #828: uninitialized constant Redmine::Scm::Adapters::CommandFailed in RepositoryController
* Bug #861: Apply Filter does not work on all-project-activities view
* Bug #868: Done bar has no filling
* Bug #869: Issue option list stacked vertically instead of horizontally
* Bug #873: Incorrect error message text for groups
* Bug #882: Right click context menu doesn't show submenu icon.
* Bug #887: Stacked month (top row)
* Bug #888: Cannot edit note
* Bug #891: quotes around path when shelling out does not work on Windows
* Bug #892: CP code or test assumes ordering where none is guaranteed
* Bug #896: Enabling "Authentication required" mode returns 404s
* Bug #903: ActionView::TemplateError (undefined method `new0' for DateTime:Class)
* Bug #911: Sub-sub (and deeper) issues CSS rules are overridden
* Bug #914: comments gets striked through, when description changes before
* Bug #922: Mass assignment
* Bug #927: Reposman script problem
* Bug #929: Missing links in Issues section in left menu bar
* Bug #933: News RSS Feed tag not populating
* Bug #939: GMail documentation in configuration.yml.default out of date
* Feature #559: Group Menus
* Feature #899: Create a jQuery verison of the context menu
* Feature #906: Add Link back to Parent of Subtask
* Feature #915: default bundle install installs old pg version
* Feature #928: Increase username length limit from 30 to 60
== 2012-02-06 v3.0.0 == 2012-02-06 v3.0.0
* Bug #826: Top right toolbar items overlap for custom issues query * Bug #826: Top right toolbar items overlap for custom issues query

View File

@ -199,6 +199,7 @@ end
class Project < ActiveResource::Base class Project < ActiveResource::Base
self.headers["User-agent"] = "Redmine repository manager/#{Version}" self.headers["User-agent"] = "Redmine repository manager/#{Version}"
self.format = :xml
end end
log("querying Redmine for projects...", :level => 1); log("querying Redmine for projects...", :level => 1);

View File

@ -18,7 +18,7 @@ module ChiliProject
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 3 MAJOR = 3
MINOR = 0 MINOR = 1
PATCH = 0 PATCH = 0
TINY = PATCH # Redmine compat TINY = PATCH # Redmine compat
@ -43,7 +43,7 @@ module ChiliProject
git_dir = Rails.root.join('.git') git_dir = Rails.root.join('.git')
if File.directory? git_dir if File.directory? git_dir
git.send(:shellout, "#{git.sq_bin} --git-dir='#{git_dir}' rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp git.send(:shellout, "#{git.sq_bin} --git-dir=#{git.shell_quote git_dir.to_s} rev-parse --short=9 HEAD") { |io| io.read }.to_s.chomp
end end
end end
end end

View File

@ -212,25 +212,178 @@ Redmine::MenuManager.map :admin_menu do |menu|
end end
Redmine::MenuManager.map :project_menu do |menu| Redmine::MenuManager.map :project_menu do |menu|
menu.push :overview, { :controller => 'projects', :action => 'show' } include ProjectsHelper
menu.push :activity, { :controller => 'activities', :action => 'index' }
menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id, # TODO: refactor to a helper that is available before app/helpers along with the other procs.
:if => Proc.new { |p| p.shared_versions.any? } issue_query_proc = Proc.new { |p|
menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural ##### Taken from IssuesHelper
menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, # User can see public queries and his own queries
visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
# Project specific queries and global queries
visible << (p.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", p.id])
sidebar_queries = Query.find(:all,
:select => 'id, name',
:order => "name ASC",
:conditions => visible.conditions)
sidebar_queries.collect do |query|
Redmine::MenuManager::MenuItem.new("query-#{query.id}".to_sym, { :controller => 'issues', :action => 'index', :project_id => p, :query_id => query }, {
:caption => query.name,
:param => :project_id,
:parent => :issues
})
end
}
menu.push(:overview, { :controller => 'projects', :action => 'show' })
menu.push(:activity, { :controller => 'activities', :action => 'index' })
menu.push(:roadmap, { :controller => 'versions', :action => 'index' }, {
:param => :project_id,
:if => Proc.new { |p| p.shared_versions.any? },
:children => Proc.new { |p|
versions = p.shared_versions.sort
versions.reject! {|version| version.closed? || version.completed? }
versions.collect do |version|
Redmine::MenuManager::MenuItem.new("version-#{version.id}".to_sym,
{ :controller => 'versions', :action => 'show', :id => version },
{
:caption => version.name,
:parent => :roadmap
})
end
}
})
menu.push(:issues, { :controller => 'issues', :action => 'index' }, {
:param => :project_id,
:caption => :label_issue_plural,
:children => issue_query_proc
})
menu.push(:new_issue, { :controller => 'issues', :action => 'new' }, {
:param => :project_id,
:caption => :label_issue_new,
:parent => :issues,
:html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }
menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt })
menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar menu.push(:all_open_issues, { :controller => 'issues', :action => 'index', :set_filter => 1 }, {
menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural :param => :project_id,
menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural :caption => :field_issue_view_all_open,
menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id, :parent => :issues
})
menu.push(:new_query, { :controller => 'queries', :action => 'new'}, {
:param => :project_id,
:caption => :field_new_saved_query,
:parent => :issues
})
menu.push(:issue_summary, { :controller => 'reports', :action => 'issue_report' }, {
:caption => :field_issue_summary,
:parent => :issues
})
menu.push(:time_entries, { :controller => 'timelog', :action => 'index' }, {
:param => :project_id,
:if => Proc.new {|p| User.current.allowed_to?(:view_time_entries, p) }
});
menu.push(:new_time_entry, { :controller => 'timelog', :action => 'new' }, {
:param => :project_id,
:if => Proc.new {|p| User.current.allowed_to?(:log_time, p) },
:parent => :time_entries
})
menu.push(:time_entry_report, { :controller => 'time_entry_reports', :action => 'report' }, {
:param => :project_id,
:if => Proc.new {|p| User.current.allowed_to?(:view_time_entries, p) },
:parent => :time_entries
})
menu.push(:gantt, { :controller => 'gantts', :action => 'show' }, {
:param => :project_id,
:caption => :label_gantt
})
menu.push(:calendar, { :controller => 'calendars', :action => 'show' }, {
:param => :project_id,
:caption => :label_calendar
})
menu.push(:news, { :controller => 'news', :action => 'index' }, {
:param => :project_id,
:caption => :label_news_plural
})
menu.push(:new_news, {:controller => 'news', :action => 'new' }, {
:param => :project_id,
:caption => :label_news_new,
:parent => :news,
:if => Proc.new {|p| User.current.allowed_to?(:manage_news, p) }
})
menu.push(:documents, { :controller => 'documents', :action => 'index' }, {
:param => :project_id,
:caption => :label_document_plural
})
menu.push(:new_document, { :controller => 'documents', :action => 'new' }, {
:param => :project_id,
:caption => :label_document_new,
:parent => :documents,
:if => Proc.new {|p| User.current.allowed_to?(:manage_documents, p) }
})
menu.push(:wiki, { :controller => 'wiki', :action => 'show', :id => nil }, {
:param => :project_id,
:if => Proc.new { |p| p.wiki && !p.wiki.new_record? } :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, })
:if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural menu.push(:wiki_by_title, { :controller => 'wiki', :action => 'index' }, {
menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id :caption => :label_index_by_title,
menu.push :repository, { :controller => 'repositories', :action => 'show' }, :parent => :wiki,
:param => :project_id,
:if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
})
menu.push(:wiki_by_date, { :controller => 'wiki', :action => 'date_index'}, {
:caption => :label_index_by_date,
:parent => :wiki,
:param => :project_id,
:if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
})
menu.push(:boards, { :controller => 'boards', :action => 'index', :id => nil }, {
:param => :project_id,
:caption => :label_board_plural,
:if => Proc.new { |p| p.boards.any? },
:children => Proc.new {|project|
project.boards.collect do |board|
Redmine::MenuManager::MenuItem.new(
"board-#{board.id}".to_sym,
{ :controller => 'boards', :action => 'show', :id => board },
{
:caption => board.name # is h() in menu_helper.rb
})
end
}
})
menu.push(:new_board, { :controller => 'boards', :action => 'new' }, {
:caption => :label_board_new,
:param => :project_id,
:parent => :boards,
:if => Proc.new {|p| User.current.allowed_to?(:manage_boards, p) }
})
menu.push(:files, { :controller => 'files', :action => 'index' }, {
:caption => :label_file_plural,
:param => :project_id
})
menu.push(:new_file, { :controller => 'files', :action => 'new' }, {
:caption => :label_attachment_new,
:param => :project_id,
:parent => :files,
:if => Proc.new {|p| User.current.allowed_to?(:manage_files, p) }
})
menu.push(:repository, { :controller => 'repositories', :action => 'show' }, {
:if => Proc.new { |p| p.repository && !p.repository.new_record? } :if => Proc.new { |p| p.repository && !p.repository.new_record? }
menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true })
menu.push(:settings, { :controller => 'projects', :action => 'settings' }, {
:last => true,
:children => Proc.new { |p|
@project = p # @project used in the helper
project_settings_tabs.collect do |tab|
Redmine::MenuManager::MenuItem.new("settings-#{tab[:name]}".to_sym,
{ :controller => 'projects', :action => 'settings', :id => p, :tab => tab[:name] },
{
:caption => tab[:label]
})
end
}
})
end end
Redmine::Activity.map do |activity| Redmine::Activity.map do |activity|

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
module Redmine module Redmine
module Scm module Scm

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
require 'rexml/document' require 'rexml/document'
module Redmine module Redmine

View File

@ -12,7 +12,7 @@
# See doc/COPYRIGHT.rdoc for more details. # See doc/COPYRIGHT.rdoc for more details.
#++ #++
require 'redmine/scm/adapters/abstract_adapter' require_dependency 'redmine/scm/adapters/abstract_adapter'
require 'find' require 'find'
module Redmine module Redmine

Some files were not shown because too many files have changed in this diff Show More