# HG changeset patch # User Chris Cannam # Date 1342009813 -3600 # Node ID d36724ef856a3db557e01d5172eddc5861421fc0 # Parent 9ee5fd0b9bd3613986af6cdabf42ac1408cf1f53# Parent ec1c49528f3655d45bb7f58dc8a77c2bc4886a2c Merge from branch "cannam_integration" diff -r 9ee5fd0b9bd3 -r d36724ef856a .svn/wc.db Binary file .svn/wc.db has changed diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/admin_controller.rb --- a/app/controllers/admin_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/admin_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -73,9 +73,7 @@ def info @db_adapter_name = ActiveRecord::Base.connection.adapter_name @checklist = [ - [:text_default_administrator_account_changed, - User.find(:first, - :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?], + [:text_default_administrator_account_changed, User.default_admin_account_changed?], [:text_file_repository_writable, File.writable?(Attachment.storage_path)], [:text_plugin_assets_writable, File.writable?(Engines.public_directory)], [:text_rmagick_available, Object.const_defined?(:Magick)] diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/boards_controller.rb --- a/app/controllers/boards_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/boards_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -65,7 +65,8 @@ verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } def new - @board = Board.new(params[:board]) + @board = Board.new + @board.safe_attributes = params[:board] @board.project = @project if request.post? && @board.save flash[:notice] = l(:notice_successful_create) @@ -74,7 +75,8 @@ end def edit - if request.post? && @board.update_attributes(params[:board]) + @board.safe_attributes = params[:board] + if request.post? && @board.save redirect_to_settings_in_projects end end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/comments_controller.rb --- a/app/controllers/comments_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/comments_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -7,7 +7,8 @@ verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create - @comment = Comment.new(params[:comment]) + @comment = Comment.new + @comment.safe_attributes = params[:comment] @comment.author = User.current if @news.comments << @comment flash[:notice] = l(:label_comment_added) diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/documents_controller.rb --- a/app/controllers/documents_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/documents_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -47,7 +47,8 @@ end def new - @document = @project.documents.build(params[:document]) + @document = @project.documents.build + @document.safe_attributes = params[:document] if request.post? and @document.save attachments = Attachment.attach_files(@document, params[:attachments]) render_attachment_warning_if_needed(@document) @@ -58,7 +59,8 @@ def edit @categories = DocumentCategory.active #TODO: use it in the views - if request.post? and @document.update_attributes(params[:document]) + @document.safe_attributes = params[:document] + if request.post? and @document.save flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :id => @document end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/issue_categories_controller.rb --- a/app/controllers/issue_categories_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/issue_categories_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -39,12 +39,14 @@ end def new - @category = @project.issue_categories.build(params[:issue_category]) + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] end verify :method => :post, :only => :create def create - @category = @project.issue_categories.build(params[:issue_category]) + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] if @category.save respond_to do |format| format.html do @@ -75,7 +77,8 @@ verify :method => :put, :only => :update def update - if @category.update_attributes(params[:issue_category]) + @category.safe_attributes = params[:issue_category] + if @category.save respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/members_controller.rb --- a/app/controllers/members_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/members_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -39,7 +39,7 @@ attrs = params[:member].dup if (user_ids = attrs.delete(:user_ids)) user_ids.each do |user_id| - @new_member = Member.new(attrs.merge(:user_id => user_id)) + @new_member = Member.new(:role_ids => params[:member][:role_ids], :user_id => user_id) members << @new_member # send notification to member @@ -47,7 +47,7 @@ end else - @new_member = Member.new(attrs) + @new_member = Member.new(:role_ids => params[:member][:role_ids], :user_id => params[:member][:user_id]) members << @new_member # send notification to member @@ -87,7 +87,10 @@ end def edit - if request.post? and @member.update_attributes(params[:member]) + if params[:member] + @member.role_ids = params[:member][:role_ids] + end + if request.post? and @member.save respond_to do |format| format.html { redirect_to :action => 'index', :project_id => @project } format.js { @@ -116,7 +119,7 @@ end def autocomplete_for_member - @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals + @principals = Principal.active.not_member_of(@project).like(params[:q]).all(:limit => 100) logger.debug "Query for #{params[:q]} returned #{@principals.size} results" render :layout => false end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/messages_controller.rb --- a/app/controllers/messages_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/messages_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -53,13 +53,10 @@ # Create a new topic def new - @message = Message.new(params[:message]) + @message = Message.new @message.author = User.current @message.board = @board - if params[:message] && User.current.allowed_to?(:edit_messages, @project) - @message.locked = params[:message]['locked'] - @message.sticky = params[:message]['sticky'] - end + @message.safe_attributes = params[:message] if request.post? && @message.save call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) attachments = Attachment.attach_files(@message, params[:attachments]) @@ -70,9 +67,10 @@ # Reply to a topic def reply - @reply = Message.new(params[:reply]) + @reply = Message.new @reply.author = User.current @reply.board = @board + @reply.safe_attributes = params[:reply] @topic.children << @reply if !@reply.new_record? call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) @@ -85,11 +83,8 @@ # Edit a message def edit (render_403; return false) unless @message.editable_by?(User.current) - if params[:message] - @message.locked = params[:message]['locked'] - @message.sticky = params[:message]['sticky'] - end - if request.post? && @message.update_attributes(params[:message]) + @message.safe_attributes = params[:message] + if request.post? && @message.save attachments = Attachment.attach_files(@message, params[:attachments]) render_attachment_warning_if_needed(@message) flash[:notice] = l(:notice_successful_update) diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/news_controller.rb --- a/app/controllers/news_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/news_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -67,8 +67,8 @@ def create @news = News.new(:project => @project, :author => User.current) + @news.safe_attributes = params[:news] if request.post? - @news.attributes = params[:news] if @news.save flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'news', :action => 'index', :project_id => @project @@ -82,7 +82,8 @@ end def update - if request.put? and @news.update_attributes(params[:news]) + @news.safe_attributes = params[:news] + if request.put? and @news.save flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :id => @news else diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/projects_controller.rb --- a/app/controllers/projects_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/projects_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -79,7 +79,8 @@ def new @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all - @project = Project.new(params[:project]) + @project = Project.new + @project.safe_attributes = params[:project] end verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/timelog_controller.rb --- a/app/controllers/timelog_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/timelog_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -105,7 +105,7 @@ def new @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 }) render :action => 'edit' @@ -114,7 +114,7 @@ verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @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 }) @@ -135,14 +135,14 @@ end 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 }) end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } 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 }) @@ -173,7 +173,7 @@ unsaved_time_entry_ids = [] @time_entries.each do |time_entry| time_entry.reload - time_entry.attributes = attributes + time_entry.safe_attributes = attributes call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) unless time_entry.save # Keep unsaved time_entry ids to display them in flash error diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/versions_controller.rb --- a/app/controllers/versions_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/versions_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -23,7 +23,7 @@ before_filter :find_project, :only => [:index, :new, :create, :close_completed] before_filter :authorize - accept_api_auth :index, :create, :update, :destroy + accept_api_auth :index, :show, :create, :update, :destroy helper :custom_fields helper :projects @@ -75,7 +75,7 @@ if params[:version] attributes = params[:version].dup attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) - @version.attributes = attributes + @version.safe_attributes = attributes end end @@ -85,7 +85,7 @@ if params[:version] attributes = params[:version].dup attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) - @version.attributes = attributes + @version.safe_attributes = attributes end if request.post? @@ -124,7 +124,8 @@ if request.put? && params[:version] attributes = params[:version].dup attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) - if @version.update_attributes(attributes) + @version.safe_attributes = attributes + if @version.save respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) diff -r 9ee5fd0b9bd3 -r d36724ef856a app/controllers/wikis_controller.rb --- a/app/controllers/wikis_controller.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/controllers/wikis_controller.rb Wed Jul 11 13:30:13 2012 +0100 @@ -22,7 +22,7 @@ # Create or update a project's wiki def edit @wiki = @project.wiki || Wiki.new(:project => @project) - @wiki.attributes = params[:wiki] + @wiki.safe_attributes = params[:wiki] @wiki.save if request.post? render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'} end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/helpers/application_helper.rb --- a/app/helpers/application_helper.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/helpers/application_helper.rb Wed Jul 11 13:30:13 2012 +0100 @@ -497,12 +497,16 @@ text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) @parsed_headings = [] + @heading_anchors = {} @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) text = parse_non_pre_blocks(text) do |text| - [:parse_sections, :parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros, :parse_headings].each do |method_name| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_macros].each do |method_name| send method_name, text, project, obj, attr, only_path, options end end + parse_headings(text, project, obj, attr, only_path, options) if @parsed_headings.any? replace_toc(text, @parsed_headings) @@ -785,6 +789,11 @@ anchor = sanitize_anchor_name(item) # used for single-file wiki export anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) + @heading_anchors[anchor] ||= 0 + idx = (@heading_anchors[anchor] += 1) + if idx > 1 + anchor = "#{anchor}-#{idx}" + end @parsed_headings << [level, anchor, item] "\n#{content}" end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/board.rb --- a/app/models/board.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/board.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Board < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :project has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" @@ -30,6 +31,8 @@ named_scope :visible, lambda {|*args| { :include => :project, :conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } } + safe_attributes 'name', 'description', 'move_to' + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_messages, project) end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/changeset.rb --- a/app/models/changeset.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/changeset.rb Wed Jul 11 13:30:13 2012 +0100 @@ -151,12 +151,16 @@ @long_comments || split_comments.last end - def text_tag - if scmid? + def text_tag(ref_project=nil) + tag = if scmid? "commit:#{scmid}" else "r#{revision}" end + if ref_project && project && ref_project != project + tag = "#{project.identifier}:#{tag}" + end + tag end # Returns the previous changeset @@ -213,7 +217,7 @@ # don't change the status is the issue is closed return if issue.status && issue.status.is_closed? - journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag)) + journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) issue.status = status unless Setting.commit_fix_done_ratio.blank? issue.done_ratio = Setting.commit_fix_done_ratio.to_i @@ -232,7 +236,7 @@ :hours => hours, :issue => issue, :spent_on => commit_date, - :comments => l(:text_time_logged_by_changeset, :value => text_tag, + :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project), :locale => Setting.default_language) ) time_entry.activity = log_time_activity unless log_time_activity.nil? diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/comment.rb --- a/app/models/comment.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/comment.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,8 +16,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Comment < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :commented, :polymorphic => true, :counter_cache => true belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' validates_presence_of :commented, :author, :comments + + safe_attributes 'comments' end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/document.rb --- a/app/models/document.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/document.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Document < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :project belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" acts_as_attachable :delete_permission => :manage_documents @@ -32,6 +33,8 @@ named_scope :visible, lambda {|*args| { :include => :project, :conditions => Project.allowed_to_condition(args.shift || User.current, :view_documents, *args) } } + safe_attributes 'category_id', 'title', 'description' + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_documents, project) end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/issue_category.rb --- a/app/models/issue_category.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/issue_category.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class IssueCategory < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :project belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' has_many :issues, :foreign_key => 'category_id', :dependent => :nullify @@ -24,7 +25,7 @@ validates_uniqueness_of :name, :scope => [:project_id] validates_length_of :name, :maximum => 30 - attr_protected :project_id + safe_attributes 'name', 'assigned_to_id' named_scope :named, lambda {|arg| { :conditions => ["LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip]}} diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/mailer.rb --- a/app/models/mailer.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/mailer.rb Wed Jul 11 13:30:13 2012 +0100 @@ -375,7 +375,7 @@ :conditions => s.conditions ).group_by(&:assigned_to) issues_by_assignee.each do |assignee, issues| - deliver_reminder(assignee, issues, days) if assignee && assignee.active? + deliver_reminder(assignee, issues, days) if assignee.is_a?(User) && assignee.active? end end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/member.rb --- a/app/models/member.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/member.rb Wed Jul 11 13:30:13 2012 +0100 @@ -50,7 +50,17 @@ def <=>(member) a, b = roles.sort.first, member.roles.sort.first - a == b ? (principal <=> member.principal) : (a <=> b) + if a == b + if principal + principal <=> member.principal + else + 1 + end + elsif a + a <=> b + else + 1 + end end def deletable? diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/message.rb --- a/app/models/message.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/message.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Message < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :board belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" @@ -36,7 +37,6 @@ :author_key => :author_id acts_as_watchable - attr_protected :locked, :sticky validates_presence_of :board, :subject, :content validates_length_of :subject, :maximum => 255 validate :cannot_reply_to_locked_topic, :on => :create @@ -48,6 +48,12 @@ named_scope :visible, lambda {|*args| { :include => {:board => :project}, :conditions => Project.allowed_to_condition(args.shift || User.current, :view_messages, *args) } } + safe_attributes 'subject', 'content' + safe_attributes 'locked', 'sticky', 'board_id', + :if => lambda {|message, user| + user.allowed_to?(:edit_messages, message.project) + } + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_messages, project) end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/news.rb --- a/app/models/news.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/news.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class News < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :project belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" @@ -37,6 +38,8 @@ :conditions => Project.allowed_to_condition(args.shift || User.current, :view_news, *args) }} + safe_attributes 'title', 'summary', 'description' + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_news, project) end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/principal.rb --- a/app/models/principal.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/principal.rb Wed Jul 11 13:30:13 2012 +0100 @@ -32,6 +32,16 @@ :order => 'type, login, lastname, firstname, mail' } } + # Principals that are not members of projects + named_scope :not_member_of, lambda {|projects| + projects = [projects] unless projects.is_a?(Array) + if projects.empty? + {:conditions => "1=0"} + else + ids = projects.map(&:id) + {:conditions => ["#{Principal.table_name}.id NOT IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids]} + end + } before_create :set_default_empty_values @@ -40,7 +50,9 @@ end def <=>(principal) - if self.class.name == principal.class.name + if principal.nil? + -1 + elsif self.class.name == principal.class.name self.to_s.downcase <=> principal.to_s.downcase else # groups after users diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/project.rb --- a/app/models/project.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/project.rb Wed Jul 11 13:30:13 2012 +0100 @@ -258,7 +258,7 @@ def to_param # id is used for projects with a numeric identifier (compatibility) - @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id : identifier) + @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id.to_s : identifier) end def active? @@ -395,16 +395,21 @@ # Returns a scope of the Versions used by the project def shared_versions - @shared_versions ||= begin - r = root? ? self : root + if new_record? Version.scoped(:include => :project, - :conditions => "#{Project.table_name}.id = #{id}" + - " OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" + + :conditions => "#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND #{Version.table_name}.sharing = 'system'") + else + @shared_versions ||= begin + r = root? ? self : root + Version.scoped(:include => :project, + :conditions => "#{Project.table_name}.id = #{id}" + + " OR (#{Project.table_name}.status = #{Project::STATUS_ACTIVE} AND (" + " #{Version.table_name}.sharing = 'system'" + " OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" + " OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" + " OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" + "))") + end end end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/time_entry.rb --- a/app/models/time_entry.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/time_entry.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class TimeEntry < ActiveRecord::Base + include Redmine::SafeAttributes # could have used polymorphic association # project association here allows easy loading of time entries at project level with one database trip belongs_to :project @@ -46,6 +47,8 @@ :conditions => Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args) }} + safe_attributes 'hours', 'comments', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values' + def after_initialize if new_record? && self.activity.nil? if default_activity = TimeEntryActivity.default diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/user.rb --- a/app/models/user.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/user.rb Wed Jul 11 13:30:13 2012 +0100 @@ -357,6 +357,11 @@ find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase]) end + # Returns true if the default admin account can no longer be used + def self.default_admin_account_changed? + !User.active.find_by_login("admin").try(:check_password?, "admin") + end + def to_s name end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/user_preference.rb --- a/app/models/user_preference.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/user_preference.rb Wed Jul 11 13:30:13 2012 +0100 @@ -19,7 +19,7 @@ belongs_to :user serialize :others - attr_protected :others + attr_protected :others, :user_id def initialize(attributes = nil) super diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/version.rb --- a/app/models/version.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/version.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Version < ActiveRecord::Base + include Redmine::SafeAttributes after_update :update_issues_from_sharing_change belongs_to :project has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify @@ -38,6 +39,15 @@ named_scope :visible, lambda {|*args| { :include => :project, :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 def visible?(user=User.current) user.allowed_to?(:view_issues, self.project) diff -r 9ee5fd0b9bd3 -r d36724ef856a app/models/wiki.rb --- a/app/models/wiki.rb Fri May 11 16:13:59 2012 +0100 +++ b/app/models/wiki.rb Wed Jul 11 13:30:13 2012 +0100 @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class Wiki < ActiveRecord::Base + include Redmine::SafeAttributes belongs_to :project has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title' has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all @@ -25,6 +26,8 @@ validates_presence_of :start_page validates_format_of :start_page, :with => /^[^,\.\/\?\;\|\:]*$/ + safe_attributes 'start_page' + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_wiki_pages, project) end diff -r 9ee5fd0b9bd3 -r d36724ef856a app/views/issues/_relations.html.erb --- a/app/views/issues/_relations.html.erb Fri May 11 16:13:59 2012 +0100 +++ b/app/views/issues/_relations.html.erb Wed Jul 11 13:30:13 2012 +0100 @@ -20,7 +20,8 @@ <%= format_date(relation.other_issue(@issue).start_date) %> <%= format_date(relation.other_issue(@issue).due_date) %> <%= link_to_remote(image_tag('link_break.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :id => relation}, - :method => :delete + :method => :delete, + :confirm => l(:text_are_you_sure) }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %> <% end %> diff -r 9ee5fd0b9bd3 -r d36724ef856a app/views/projects/settings/_members.html.erb --- a/app/views/projects/settings/_members.html.erb Fri May 11 16:13:59 2012 +0100 +++ b/app/views/projects/settings/_members.html.erb Wed Jul 11 13:30:13 2012 +0100 @@ -50,7 +50,7 @@ <% end %> -<% principals = Principal.active.find(:all, :limit => 100, :order => 'type, login, lastname ASC') - @project.principals %> +<% principals = Principal.active.not_member_of(@project).all(:limit => 100, :order => 'type, login, lastname ASC') %>
<% if roles.any? && principals.any? %> diff -r 9ee5fd0b9bd3 -r d36724ef856a config/locales/it.yml --- a/config/locales/it.yml Fri May 11 16:13:59 2012 +0100 +++ b/config/locales/it.yml Wed Jul 11 13:30:13 2012 +0100 @@ -980,7 +980,7 @@ label_between: tra setting_issue_group_assignment: Permetti di assegnare una segnalazione a gruppi label_diff: diff - text_git_repository_note: Il repository è bare e locale (e.g. /gitrepo, c:\gitrepo) + text_git_repository_note: Il repository è spoglio e locale (e.g. /gitrepo, c:\gitrepo) description_query_sort_criteria_direction: Ordinamento description_project_scope: Search scope description_filter: Filtro diff -r 9ee5fd0b9bd3 -r d36724ef856a config/locales/nl.yml --- a/config/locales/nl.yml Fri May 11 16:13:59 2012 +0100 +++ b/config/locales/nl.yml Wed Jul 11 13:30:13 2012 +0100 @@ -399,7 +399,7 @@ label_f_hour_plural: "%{value} uren" label_feed_plural: Feeds label_feeds_access_key_created_on: "RSS toegangssleutel %{value} geleden gemaakt." - label_file_added: Bericht toegevoegd + label_file_added: Bestand toegevoegd label_file_plural: Bestanden label_filter_add: Voeg filter toe label_filter_plural: Filters diff -r 9ee5fd0b9bd3 -r d36724ef856a config/locales/zh.yml --- a/config/locales/zh.yml Fri May 11 16:13:59 2012 +0100 +++ b/config/locales/zh.yml Wed Jul 11 13:30:13 2012 +0100 @@ -1003,9 +1003,9 @@ label_child_revision: 子修订 error_scm_annotate_big_text_file: 输入文本内容超长,无法输入。 setting_default_issue_start_date_to_creation_date: 使用当前日期作为新问题的开始日期 - button_edit_section: Edit this section - setting_repositories_encodings: Attachments and repositories encodings - description_all_columns: All Columns - button_export: Export - label_export_options: "%{export_format} export options" - error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + button_edit_section: 编辑此区域 + setting_repositories_encodings: 附件和版本库编码 + description_all_columns: 所有列 + button_export: 导出 + label_export_options: "%{export_format} 导出选项" + error_attachment_too_big: 该文件无法上传。超过文件大小限制 (%{max_size}) diff -r 9ee5fd0b9bd3 -r d36724ef856a doc/CHANGELOG --- a/doc/CHANGELOG Fri May 11 16:13:59 2012 +0100 +++ b/doc/CHANGELOG Wed Jul 11 13:30:13 2012 +0100 @@ -4,6 +4,36 @@ Copyright (C) 2006-2012 Jean-Philippe Lang http://www.redmine.org/ +== 2012-04-14 v1.3.3 + +* Defect #10505: Error when exporting to PDF with NoMethodError (undefined method `downcase' for nil:NilClass) +* Defect #10554: Defect symbols when exporting tasks in pdf +* Defect #10564: Unable to change locked, sticky flags and board when editing a message +* Defect #10591: Dutch "label_file_added" translation is wrong +* Defect #10622: "Default administrator account changed" is always true +* Patch #10555: rake redmine:send_reminders aborted if issue assigned to group +* Patch #10611: Simplified Chinese translations for 1.3-stable + +== 2012-03-11 v1.3.2 + +* Defect #8194: {{toc}} uses identical anchors for subsections with the same name +* Defect #9143: Partial diff comparison should be done on actual code, not on html +* Defect #9523: {{toc}} does not display headers with @ code markup +* Defect #9815: Release 1.3.0 does not detect rubytree with rubgems 1.8 +* Defect #10053: undefined method `<=>' for nil:NilClass when accessing the settings of a project +* Defect #10135: ActionView::TemplateError (can't convert Fixnum into String) +* Defect #10193: Unappropriate icons in highlighted code block +* Defect #10199: No wiki section edit when title contains code +* Defect #10218: Error when creating a project with a version custom field +* Defect #10241: "get version by ID" fails with "401 not authorized" error when using API access key +* Defect #10284: Note added by commit from a subproject does not contain project identifier +* Defect #10374: User list is empty when adding users to project / group if remaining users are added late +* Defect #10390: Mass assignment security vulnerability +* Patch #8413: Confirmation message before deleting a relationship +* Patch #10160: Bulgarian translation (r8777) +* Patch #10242: Migrate Redmine.pm from Digest::Sha1 to Digest::Sha +* Patch #10258: Italian translation for 1.3-stable + == 2012-02-06 v1.3.1 * Defect #9775: app/views/repository/_revision_graph.html.erb sets window.onload directly.. diff -r 9ee5fd0b9bd3 -r d36724ef856a extra/svn/Redmine.pm --- a/extra/svn/Redmine.pm Fri May 11 16:13:59 2012 +0100 +++ b/extra/svn/Redmine.pm Wed Jul 11 13:30:13 2012 +0100 @@ -99,7 +99,7 @@ use warnings FATAL => 'all', NONFATAL => 'redefine'; use DBI; -use Digest::SHA1; +use Digest::SHA; # optional module for LDAP authentication my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1"); @@ -327,7 +327,7 @@ my $dbh = connect_database($r); my $project_id = get_project_identifier($r); - my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); + my $pass_digest = Digest::SHA::sha1_hex($redmine_pass); my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W"; @@ -346,7 +346,7 @@ unless ($auth_source_id) { my $method = $r->method; - my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest); + my $salted_password = Digest::SHA::sha1_hex($salt.$pass_digest); if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { $ret = 1; last; diff -r 9ee5fd0b9bd3 -r d36724ef856a lib/redmine/unified_diff.rb --- a/lib/redmine/unified_diff.rb Fri May 11 16:13:59 2012 +0100 +++ b/lib/redmine/unified_diff.rb Wed Jul 11 13:30:13 2012 +0100 @@ -112,11 +112,6 @@ private - # Escape the HTML for the diff - def escapeHTML(line) - CGI.escapeHTML(line) - end - def diff_for_added_line if @type == 'sbs' && @removed > 0 && @added < @removed self[-(@removed - @added)] @@ -130,7 +125,7 @@ def parse_line(line, type="inline") if line[0, 1] == "+" diff = diff_for_added_line - diff.line_right = escapeHTML line[1..-1] + diff.line_right = line[1..-1] diff.nb_line_right = @line_num_r diff.type_diff_right = 'diff_in' @line_num_r += 1 @@ -138,7 +133,7 @@ true elsif line[0, 1] == "-" diff = Diff.new - diff.line_left = escapeHTML line[1..-1] + diff.line_left = line[1..-1] diff.nb_line_left = @line_num_l diff.type_diff_left = 'diff_out' self << diff @@ -149,9 +144,9 @@ write_offsets if line[0, 1] =~ /\s/ diff = Diff.new - diff.line_right = escapeHTML line[1..-1] + diff.line_right = line[1..-1] diff.nb_line_right = @line_num_r - diff.line_left = escapeHTML line[1..-1] + diff.line_left = line[1..-1] diff.nb_line_left = @line_num_l self << diff @line_num_l += 1 @@ -224,27 +219,15 @@ end def html_line_left - if offsets - line_left.dup.insert(offsets.first, '').insert(offsets.last, '') - else - line_left - end + line_to_html(line_left, offsets) end def html_line_right - if offsets - line_right.dup.insert(offsets.first, '').insert(offsets.last, '') - else - line_right - end + line_to_html(line_right, offsets) end def html_line - if offsets - line.dup.insert(offsets.first, '').insert(offsets.last, '') - else - line - end + line_to_html(line, offsets) end def inspect @@ -254,5 +237,23 @@ puts self.nb_line_right puts self.line_right end + + private + + def line_to_html(line, offsets) + if offsets + s = '' + unless offsets.first == 0 + s << CGI.escapeHTML(line[0..offsets.first-1]) + end + s << '' + CGI.escapeHTML(line[offsets.first..offsets.last]) + '' + unless offsets.last == -1 + s << CGI.escapeHTML(line[offsets.last+1..-1]) + end + s + else + CGI.escapeHTML(line) + end + end end end diff -r 9ee5fd0b9bd3 -r d36724ef856a lib/redmine/version.rb --- a/lib/redmine/version.rb Fri May 11 16:13:59 2012 +0100 +++ b/lib/redmine/version.rb Wed Jul 11 13:30:13 2012 +0100 @@ -4,7 +4,7 @@ module VERSION #:nodoc: MAJOR = 1 MINOR = 3 - TINY = 1 + TINY = 3 # Branch values: # * official release: nil diff -r 9ee5fd0b9bd3 -r d36724ef856a public/stylesheets/application.css --- a/public/stylesheets/application.css Fri May 11 16:13:59 2012 +0100 +++ b/public/stylesheets/application.css Wed Jul 11 13:30:13 2012 +0100 @@ -513,6 +513,9 @@ a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } +em.info {font-style:normal;font-size:90%;color:#888;display:block;} +em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} + /* Project members tab */ div#tab-content-members .splitcontentleft, div#tab-content-memberships .splitcontentleft, div#tab-content-users .splitcontentleft { width: 64% } div#tab-content-members .splitcontentright, div#tab-content-memberships .splitcontentright, div#tab-content-users .splitcontentright { width: 34% } @@ -566,8 +569,6 @@ color: #A6750C; } -span.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} - #errorExplanation ul { font-size: 0.9em;} #errorExplanation h2, #errorExplanation p { display: none; } diff -r 9ee5fd0b9bd3 -r d36724ef856a test/functional/boards_controller_test.rb --- a/test/functional/boards_controller_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/functional/boards_controller_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -88,6 +88,14 @@ assert_equal 'Testing', Board.find(2).name end + def test_update_position + @request.session[:user_id] = 2 + post :edit, :project_id => 1, :id => 2, :board => { :move_to => 'highest'} + assert_redirected_to '/projects/ecookbook/settings/boards' + board = Board.find(2) + assert_equal 1, board.position + end + def test_post_destroy @request.session[:user_id] = 2 assert_difference 'Board.count', -1 do diff -r 9ee5fd0b9bd3 -r d36724ef856a test/functional/issues_controller_test.rb --- a/test/functional/issues_controller_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/functional/issues_controller_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -147,7 +147,6 @@ end def test_index_with_short_filters - to_test = { 'status_id' => { 'o' => { :op => 'o', :values => [''] }, @@ -181,9 +180,9 @@ 't-2' => { :op => 't-', :values => ['2'] }}, 'created_on' => { '>=2011-10-12' => { :op => '>=', :values => ['2011-10-12'] }, - ' { :op => '=', :values => ['t+2' => { :op => '=', :values => ['>t+2'] }, - 't+2' => { :op => 't', :values => ['+2'] }}, + ' { :op => ' ['2'] }, + '>t-2' => { :op => '>t-', :values => ['2'] }, + 't-2' => { :op => 't-', :values => ['2'] }}, 'cf_1' => { 'c' => { :op => '=', :values => ['c'] }, '!c' => { :op => '!', :values => ['c'] }, @@ -215,7 +214,6 @@ assert_equal(default_filter.merge({field => {:operator => expected[:op], :values => expected[:values]}}), query.filters) end end - end def test_index_with_project_and_empty_filters @@ -933,7 +931,7 @@ def test_post_new_with_group_assignment group = Group.find(11) project = Project.find(1) - project.members << Member.new(:principal => group, :roles => [Role.first]) + project.members << Member.new(:principal => group, :roles => [Role.givable.first]) with_settings :issue_group_assignment => '1' do @request.session[:user_id] = 2 @@ -1803,7 +1801,7 @@ def test_bulk_update_with_group_assignee group = Group.find(11) project = Project.find(1) - project.members << Member.new(:principal => group, :roles => [Role.first]) + project.members << Member.new(:principal => group, :roles => [Role.givable.first]) @request.session[:user_id] = 2 # update issues assignee diff -r 9ee5fd0b9bd3 -r d36724ef856a test/functional/messages_controller_test.rb --- a/test/functional/messages_controller_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/functional/messages_controller_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -131,6 +131,30 @@ assert_equal 'New body', message.content end + def test_post_edit_sticky_and_locked + @request.session[:user_id] = 2 + post :edit, :board_id => 1, :id => 1, + :message => { :subject => 'New subject', + :content => 'New body', + :locked => '1', + :sticky => '1'} + assert_redirected_to '/boards/1/topics/1' + message = Message.find(1) + assert_equal true, message.sticky? + assert_equal true, message.locked? + end + + def test_post_edit_should_allow_to_change_board + @request.session[:user_id] = 2 + post :edit, :board_id => 1, :id => 1, + :message => { :subject => 'New subject', + :content => 'New body', + :board_id => 2} + assert_redirected_to '/boards/2/topics/1' + message = Message.find(1) + assert_equal Board.find(2), message.board + end + def test_reply @request.session[:user_id] = 2 post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' } diff -r 9ee5fd0b9bd3 -r d36724ef856a test/functional/project_enumerations_controller_test.rb --- a/test/functional/project_enumerations_controller_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/functional/project_enumerations_controller_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -13,6 +13,8 @@ :custom_fields_trackers, :custom_values, :time_entries + self.use_transactional_fixtures = false + def setup @request.session[:user_id] = nil Setting.default_language = 'en' diff -r 9ee5fd0b9bd3 -r d36724ef856a test/functional/trackers_controller_test.rb --- a/test/functional/trackers_controller_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/functional/trackers_controller_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -64,7 +64,7 @@ tracker = Tracker.first(:order => 'id DESC') assert_equal 'New tracker', tracker.name assert_equal [1], tracker.project_ids.sort - assert_equal [1, 6], tracker.custom_field_ids + assert_equal [1, 6], tracker.custom_field_ids.sort assert_equal 0, tracker.workflows.count end diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/changeset_test.rb --- a/test/unit/changeset_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/changeset_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -178,6 +178,24 @@ assert c.issues.first.project != c.project end + def test_commit_closing_a_subproject_issue + with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do + issue = Issue.find(5) + assert !issue.closed? + assert_difference 'Journal.count' do + c = Changeset.new(:repository => Project.find(1).repository, + :committed_on => Time.now, + :comments => 'closes #5, a subproject issue', + :revision => '12345') + assert c.save + end + assert issue.reload.closed? + journal = Journal.first(:order => 'id DESC') + assert_equal issue, journal.issue + assert_include "Applied in changeset ecookbook:r12345.", journal.notes + end + end + def test_commit_referencing_a_parent_project_issue # repository of child project r = Repository::Subversion.create!( @@ -197,6 +215,16 @@ assert_equal 'r520', c.text_tag end + def test_text_tag_revision_with_same_project + c = Changeset.new(:revision => '520', :repository => Project.find(1).repository) + assert_equal 'r520', c.text_tag(Project.find(1)) + end + + def test_text_tag_revision_with_different_project + c = Changeset.new(:revision => '520', :repository => Project.find(1).repository) + assert_equal 'ecookbook:r520', c.text_tag(Project.find(2)) + end + def test_text_tag_hash c = Changeset.new( :scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518', @@ -204,6 +232,16 @@ assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag end + def test_text_tag_hash_with_same_project + c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository) + assert_equal 'commit:7234cb27', c.text_tag(Project.find(1)) + end + + def test_text_tag_hash_with_different_project + c = Changeset.new(:revision => '7234cb27', :scmid => '7234cb27', :repository => Project.find(1).repository) + assert_equal 'ecookbook:commit:7234cb27', c.text_tag(Project.find(2)) + end + def test_text_tag_hash_all_number c = Changeset.new(:scmid => '0123456789', :revision => '0123456789') assert_equal 'commit:0123456789', c.text_tag diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/helpers/application_helper_test.rb --- a/test/unit/helpers/application_helper_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/helpers/application_helper_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -732,6 +732,8 @@ h3. Subtitle with *some* _modifiers_ +h3. Subtitle with @inline code@ + h1. Another title h3. An "Internet link":http://www.redmine.org/ inside subtitle @@ -748,6 +750,7 @@ '
  • Subtitle with red text' + '' + '
  • ' + '' + @@ -768,6 +771,33 @@ assert textilizable(raw).gsub("\n", "").include?(expected) end + def test_table_of_content_should_generate_unique_anchors + raw = <<-RAW +{{toc}} + +h1. Title + +h2. Subtitle + +h2. Subtitle +RAW + + expected = '' + + @project = Project.find(1) + result = textilizable(raw).gsub("\n", "") + assert_include expected, result + assert_include '', result + assert_include '', result + end + def test_table_of_content_should_contain_included_page_headings raw = <<-RAW {{toc}} @@ -786,6 +816,48 @@ assert textilizable(raw).gsub("\n", "").include?(expected) end + def test_section_edit_links + raw = <<-RAW +h1. Title + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas sed libero. + +h2. Subtitle with a [[Wiki]] link + +h2. Subtitle with *some* _modifiers_ + +h2. Subtitle with @inline code@ + +
    +some code
    +
    +h2. heading inside pre
    +
    +

    html heading inside pre

    +
    + +h2. Subtitle after pre tag +RAW + + @project = Project.find(1) + set_language_if_valid 'en' + result = textilizable(raw, :edit_section_links => {:controller => 'wiki', :action => 'edit', :project_id => '1', :id => 'Test'}).gsub("\n", "") + + # heading that contains inline code + assert_match Regexp.new('
    ' + + '' + + '

    Subtitle with inline code

    '), + result + + # last heading + assert_match Regexp.new('
    ' + + 'Edit
    ' + + '' + + '

    Subtitle after pre tag

    '), + result + end + def test_default_formatter Setting.text_formatting = 'unknown' text = 'a *link*: http://www.example.net/' @@ -853,6 +925,14 @@ link_to_project(project, {:action => 'settings'}, :class => "project") end + def test_link_to_legacy_project_with_numerical_identifier_should_use_id + # numeric identifier are no longer allowed + Project.update_all "identifier=25", "id=1" + + assert_equal 'eCookbook', + link_to_project(Project.find(1)) + end + def test_principals_options_for_select_with_users users = [User.find(2), User.find(4)] assert_equal %(), diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/lib/redmine/unified_diff_test.rb --- a/test/unit/lib/redmine/unified_diff_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/lib/redmine/unified_diff_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -91,6 +91,29 @@ end + def test_partials_with_html_entities + raw = <<-DIFF +--- test.orig.txt Wed Feb 15 16:10:39 2012 ++++ test.new.txt Wed Feb 15 16:11:25 2012 +@@ -1,5 +1,5 @@ + Semicolons were mysteriously appearing in code diffs in the repository + +-void DoSomething(std::auto_ptr myObj) ++void DoSomething(const MyClass& myObj) + +DIFF + + diff = Redmine::UnifiedDiff.new(raw, :type => 'sbs') + assert_equal 1, diff.size + assert_equal 'void DoSomething(std::auto_ptr<MyClass> myObj)', diff.first[2].html_line_left + assert_equal 'void DoSomething(const MyClass& myObj)', diff.first[2].html_line_right + + diff = Redmine::UnifiedDiff.new(raw, :type => 'inline') + assert_equal 1, diff.size + assert_equal 'void DoSomething(std::auto_ptr<MyClass> myObj)', diff.first[2].html_line + assert_equal 'void DoSomething(const MyClass& myObj)', diff.first[3].html_line + end + def test_line_starting_with_dashes diff = Redmine::UnifiedDiff.new(<<-DIFF --- old.txt Wed Nov 11 14:24:58 2009 diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/mailer_test.rb --- a/test/unit/mailer_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/mailer_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -370,7 +370,7 @@ end def test_wiki_content_added - content = WikiContent.find(:first) + content = WikiContent.find(1) valid_languages.each do |lang| Setting.default_language = lang.to_s assert_difference 'ActionMailer::Base.deliveries.size' do @@ -380,7 +380,7 @@ end def test_wiki_content_updated - content = WikiContent.find(:first) + content = WikiContent.find(1) valid_languages.each do |lang| Setting.default_language = lang.to_s assert_difference 'ActionMailer::Base.deliveries.size' do diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/member_test.rb --- a/test/unit/member_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/member_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -82,6 +82,23 @@ assert_raise(ActiveRecord::RecordNotFound) { Member.find(@jsmith.id) } end + def test_sort_without_roles + a = Member.new(:roles => [Role.first]) + b = Member.new + + assert_equal -1, a <=> b + assert_equal 1, b <=> a + end + + def test_sort_without_principal + role = Role.first + a = Member.new(:roles => [role], :principal => User.first) + b = Member.new(:roles => [role]) + + assert_equal -1, a <=> b + assert_equal 1, b <=> a + end + context "removing permissions" do setup do Watcher.delete_all("user_id = 9") diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/news_test.rb --- a/test/unit/news_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/news_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -30,7 +30,7 @@ def test_create_should_send_email_notification ActionMailer::Base.deliveries.clear Setting.notified_events << 'news_added' - news = Project.find(:first).news.new(valid_news) + news = Project.find(1).news.new(valid_news) assert news.save assert_equal 1, ActionMailer::Base.deliveries.size diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/principal_test.rb --- a/test/unit/principal_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/principal_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -18,6 +18,13 @@ require File.expand_path('../../test_helper', __FILE__) class PrincipalTest < ActiveSupport::TestCase + fixtures :users, :projects, :members, :member_roles + + def test_not_member_of_scope_should_return_users_that_have_no_memberships + projects = Project.find_all_by_id(1, 2) + expected = (Principal.all - projects.map(&:memberships).flatten.map(&:principal)).sort + assert_equal expected, Principal.not_member_of(projects).sort + end context "#like" do setup do diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/project_test.rb --- a/test/unit/project_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/project_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -96,8 +96,8 @@ assert_equal ['issue_tracking', 'repository'], Project.new.enabled_module_names end - assert_equal Tracker.all, Project.new.trackers - assert_equal Tracker.find(1, 3), Project.new(:tracker_ids => [1, 3]).trackers + assert_equal Tracker.all.sort, Project.new.trackers.sort + assert_equal Tracker.find(1, 3).sort, Project.new(:tracker_ids => [1, 3]).trackers.sort end def test_update @@ -586,6 +586,13 @@ assert !versions.collect(&:id).include?(6) end + def test_shared_versions_for_new_project_should_include_system_shared_versions + p = Project.find(5) + v = Version.create!(:name => 'system_sharing', :project => p, :sharing => 'system') + + assert_include v, Project.new.shared_versions + end + def test_next_identifier ProjectCustomField.delete_all Project.create!(:name => 'last', :identifier => 'p2008040') diff -r 9ee5fd0b9bd3 -r d36724ef856a test/unit/user_test.rb --- a/test/unit/user_test.rb Fri May 11 16:13:59 2012 +0100 +++ b/test/unit/user_test.rb Wed Jul 11 13:30:13 2012 +0100 @@ -574,6 +574,38 @@ end end + def test_default_admin_account_changed_should_return_false_if_account_was_not_changed + user = User.find_by_login("admin") + user.password = "admin" + user.save! + + assert_equal false, User.default_admin_account_changed? + end + + def test_default_admin_account_changed_should_return_true_if_password_was_changed + user = User.find_by_login("admin") + user.password = "newpassword" + user.save! + + assert_equal true, User.default_admin_account_changed? + end + + def test_default_admin_account_changed_should_return_true_if_account_is_disabled + user = User.find_by_login("admin") + user.password = "admin" + user.status = User::STATUS_LOCKED + user.save! + + assert_equal true, User.default_admin_account_changed? + end + + def test_default_admin_account_changed_should_return_true_if_account_does_not_exist + user = User.find_by_login("admin") + user.destroy + + assert_equal true, User.default_admin_account_changed? + end + def test_roles_for_project # user with a role roles = @jsmith.roles_for_project(Project.find(1)) diff -r 9ee5fd0b9bd3 -r d36724ef856a vendor/gems/rubytree-0.5.2/.specification --- a/vendor/gems/rubytree-0.5.2/.specification Fri May 11 16:13:59 2012 +0100 +++ b/vendor/gems/rubytree-0.5.2/.specification Wed Jul 11 13:30:13 2012 +0100 @@ -11,17 +11,8 @@ date: 2007-12-20 00:00:00 -08:00 default_executable: -dependencies: -- !ruby/object:Gem::Dependency - name: hoe - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.3.0 - version: +dependencies: [] + description: "Provides a generic tree data-structure with ability to store keyed node-elements in the tree. The implementation mixes in the Enumerable module. Website: http://rubytree.rubyforge.org/" email: anupamsg@gmail.com executables: [] diff -r 9ee5fd0b9bd3 -r d36724ef856a vendor/plugins/redmine_tags/app/views/projects/_tags_form.html.erb --- a/vendor/plugins/redmine_tags/app/views/projects/_tags_form.html.erb Fri May 11 16:13:59 2012 +0100 +++ b/vendor/plugins/redmine_tags/app/views/projects/_tags_form.html.erb Wed Jul 11 13:30:13 2012 +0100 @@ -1,8 +1,11 @@ <% fields_for :project, project, :builder => TabularFormBuilder do |f| -%>
    -

    <%= f.text_field :tag_list, :label => :tags, :size => 60, :class => 'hol' %>

    +

    <%= f.text_field :tag_list, :label => :tags, :size => 60, :class => 'hol' %> +
    + <%= l(:text_tags_info) %> +

    <%= javascript_include_tag 'tags_input', :plugin => 'redmine_tags' %> - <%= javascript_tag "observeProjectTagsField('#{url_for(:controller => 'auto_completes', :action => 'project_tags', :project_id => Project.first.id)}', false)" %> + <%= javascript_tag "observeProjectTagsField('#{url_for(:controller => 'auto_completes', :action => 'project_tags', :project_id => Project.first.id)}', false)" %>
    <% end -%> \ No newline at end of file diff -r 9ee5fd0b9bd3 -r d36724ef856a vendor/plugins/redmine_tags/config/locales/en.yml --- a/vendor/plugins/redmine_tags/config/locales/en.yml Fri May 11 16:13:59 2012 +0100 +++ b/vendor/plugins/redmine_tags/config/locales/en.yml Wed Jul 11 13:30:13 2012 +0100 @@ -39,3 +39,7 @@ project_filtering_q_label: "Search for text:" project_filter_no_results: "No matching projects found" button_filter: "Filter" + + text_tags_info: "A tag can be any text you like, but they're most useful if you choose tags that are already being used for the same thing by other projects (where possible).
    Some tag examples are: library, plugin, paper, c++, mir, alpha, stable, bsd, android, ...
    Tags help others find your work: please don't forget to tag your projects!" + + diff -r 9ee5fd0b9bd3 -r d36724ef856a vendor/plugins/rfpdf/lib/tcpdf.rb --- a/vendor/plugins/rfpdf/lib/tcpdf.rb Fri May 11 16:13:59 2012 +0100 +++ b/vendor/plugins/rfpdf/lib/tcpdf.rb Wed Jul 11 13:30:13 2012 +0100 @@ -1803,7 +1803,7 @@ w = @w - @r_margin - @x; end - wmax = (w - 2 * @c_margin); + wmax = (w - 3 * @c_margin); s = txt.gsub("\r", ''); # remove carriage returns nb = s.length; @@ -1862,7 +1862,7 @@ ns += 1; end - l = GetStringWidth(s[from_j, to_index - from_j + 1]); + l = GetStringWidth(s[from_j, to_index - from_j]); if (l > wmax) #Automatic line break @@ -1945,7 +1945,7 @@ #Output text in flowing mode w = @w - @r_margin - @x; - wmax = (w - 2 * @c_margin); + wmax = (w - 3 * @c_margin); s = txt.gsub("\r", ''); nb = s.length; @@ -1974,7 +1974,7 @@ if (nl == 1) @x = @l_margin; w = @w - @r_margin - @x; - wmax = (w - 2 * @c_margin); + wmax = (w - 3 * @c_margin); end nl += 1; next @@ -1982,7 +1982,7 @@ if (c == " "[0]) sep= i; end - l = GetStringWidth(s[j, i - j + 1]); + l = GetStringWidth(s[j, i - j]); if (l > wmax) #Automatic line break (word wrapping) if (sep == -1) @@ -1991,7 +1991,7 @@ @x = @l_margin; @y += h; w=@w - @r_margin - @x; - wmax=(w - 2 * @c_margin); + wmax=(w - 3 * @c_margin); i += 1 nl += 1 next @@ -2010,7 +2010,7 @@ if (nl==1) @x = @l_margin; w = @w - @r_margin - @x; - wmax = (w - 2 * @c_margin); + wmax = (w - 3 * @c_margin); end nl += 1; else @@ -3474,7 +3474,7 @@ #Extract attributes # get tag name tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0} - tag = tag[0].downcase; + tag = tag[0].to_s.downcase; # get attributes attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/) @@ -3497,7 +3497,7 @@ #Extract attributes # get tag name tag = element.scan(/([a-zA-Z0-9]*)/).flatten.delete_if {|x| x.length == 0} - tag = tag[0].downcase; + tag = tag[0].to_s.downcase; # get attributes attr_array = element.scan(/([^=\s]*)=["\']?([^"\']*)["\']?/)