Compare commits

..
1 Commits
Author SHA1 Message Date
Jean-Philippe Lang 1919f61fa1 tagged version 0.9.2
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/0.9.2@3421 e93f8b46-1217-0410-a6f0-8f06a7374b81
2010-02-13 09:45:46 +00:00
129 changed files with 317 additions and 912 deletions
+5 -10
View File
@@ -25,7 +25,8 @@ class AccountController < ApplicationController
# Login request and validation # Login request and validation
def login def login
if request.get? if request.get?
logout_user # Logout user
self.logged_user = nil
else else
# Authenticate user # Authenticate user
if Setting.openid? && using_open_id? if Setting.openid? && using_open_id?
@@ -38,7 +39,9 @@ class AccountController < ApplicationController
# Log out current user and redirect to welcome page # Log out current user and redirect to welcome page
def logout def logout
logout_user cookies.delete :autologin
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) if User.current.logged?
self.logged_user = nil
redirect_to home_url redirect_to home_url
end end
@@ -132,14 +135,6 @@ class AccountController < ApplicationController
private private
def logout_user
if User.current.logged?
cookies.delete :autologin
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin'])
self.logged_user = nil
end
end
def password_authentication def password_authentication
user = User.try_to_login(params[:username], params[:password]) user = User.try_to_login(params[:username], params[:password])
+1 -2
View File
@@ -107,9 +107,8 @@ class ApplicationController < ActionController::Base
lang = find_language(User.current.language) lang = find_language(User.current.language)
end end
if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE'] if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE']
accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase
if !accept_lang.blank? if !accept_lang.blank?
accept_lang = accept_lang.downcase
lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) lang = find_language(accept_lang) || find_language(accept_lang.split('-').first)
end end
end end
+2 -2
View File
@@ -76,12 +76,12 @@ class EnumerationsController < ApplicationController
@enumeration.destroy @enumeration.destroy
redirect_to :action => 'index' redirect_to :action => 'index'
elsif params[:reassign_to_id] elsif params[:reassign_to_id]
if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) if reassign_to = Enumeration.find_by_type_and_id(@enumeration.type, params[:reassign_to_id])
@enumeration.destroy(reassign_to) @enumeration.destroy(reassign_to)
redirect_to :action => 'index' redirect_to :action => 'index'
end end
end end
@enumerations = @enumeration.class.find(:all) - [@enumeration] @enumerations = Enumeration.find(:all, :conditions => ['type = (?)', @enumeration.type]) - [@enumeration]
#rescue #rescue
# flash[:error] = 'Unable to delete enumeration' # flash[:error] = 'Unable to delete enumeration'
# redirect_to :action => 'index' # redirect_to :action => 'index'
@@ -21,8 +21,8 @@ class IssueRelationsController < ApplicationController
def new def new
@relation = IssueRelation.new(params[:relation]) @relation = IssueRelation.new(params[:relation])
@relation.issue_from = @issue @relation.issue_from = @issue
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/) if params[:relation] && !params[:relation][:issue_to_id].blank?
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i) @relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id])
end end
@relation.save if request.post? @relation.save if request.post?
respond_to do |format| respond_to do |format|
+12 -8
View File
@@ -149,7 +149,7 @@ class IssuesController < ApplicationController
if request.get? || request.xhr? if request.get? || request.xhr?
@issue.start_date ||= Date.today @issue.start_date ||= Date.today
else else
requested_status = IssueStatus.find_by_id(params[:issue][:status_id]) if params[:issue] requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
# Check that the user is allowed to apply the requested status # Check that the user is allowed to apply the requested status
@issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status @issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
@@ -223,13 +223,10 @@ class IssuesController < ApplicationController
user = @issue.author user = @issue.author
text = @issue.description text = @issue.description
end end
# Replaces pre blocks with [...] content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
text = text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]') content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> "
content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n"
render(:update) { |page| render(:update) { |page|
page.<< "$('notes').value = \"#{escape_javascript content}\";" page.<< "$('notes').value = \"#{content}\";"
page.show 'update' page.show 'update'
page << "Form.Element.focus('notes');" page << "Form.Element.focus('notes');"
page << "Element.scrollTo('update');" page << "Element.scrollTo('update');"
@@ -283,7 +280,14 @@ class IssuesController < ApplicationController
def move def move
@copy = params[:copy_options] && params[:copy_options][:copy] @copy = params[:copy_options] && params[:copy_options][:copy]
@allowed_projects = Issue.allowed_target_projects_on_move @allowed_projects = []
# find projects to which the user is allowed to move the issue
if User.current.admin?
# admin is allowed to move issues to any active (visible) project
@allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current))
else
User.current.memberships.each {|m| @allowed_projects << m.project if m.roles.detect {|r| r.allowed_to?(:move_issues)}}
end
@target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]
@target_project ||= @project @target_project ||= @project
@trackers = @target_project.trackers @trackers = @target_project.trackers
+1 -7
View File
@@ -38,7 +38,6 @@ class MembersController < ApplicationController
format.js { format.js {
render(:update) {|page| render(:update) {|page|
page.replace_html "tab-content-members", :partial => 'projects/settings/members' page.replace_html "tab-content-members", :partial => 'projects/settings/members'
page << 'hideOnLoad()'
members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
} }
} }
@@ -52,7 +51,6 @@ class MembersController < ApplicationController
format.js { format.js {
render(:update) {|page| render(:update) {|page|
page.replace_html "tab-content-members", :partial => 'projects/settings/members' page.replace_html "tab-content-members", :partial => 'projects/settings/members'
page << 'hideOnLoad()'
page.visual_effect(:highlight, "member-#{@member.id}") page.visual_effect(:highlight, "member-#{@member.id}")
} }
} }
@@ -66,11 +64,7 @@ class MembersController < ApplicationController
end end
respond_to do |format| respond_to do |format|
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
format.js { render(:update) {|page| format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
page.replace_html "tab-content-members", :partial => 'projects/settings/members'
page << 'hideOnLoad()'
}
}
end end
end end
+18 -16
View File
@@ -27,7 +27,7 @@ class ProjectsController < ApplicationController
before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ] before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ]
before_filter :authorize_global, :only => :add before_filter :authorize_global, :only => :add
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
accept_key_auth :activity, :index accept_key_auth :activity
after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller| after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|
if controller.request.post? if controller.request.post?
@@ -102,20 +102,18 @@ class ProjectsController < ApplicationController
redirect_to :controller => 'admin', :action => 'projects' redirect_to :controller => 'admin', :action => 'projects'
end end
else else
Mailer.with_deliveries(params[:notifications] == '1') do @project = Project.new(params[:project])
@project = Project.new(params[:project]) @project.enabled_module_names = params[:enabled_modules]
@project.enabled_module_names = params[:enabled_modules] if validate_parent_id && @project.copy(@source_project, :only => params[:only])
if validate_parent_id && @project.copy(@source_project, :only => params[:only]) @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id')
@project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') flash[:notice] = l(:notice_successful_create)
flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'admin', :action => 'projects'
redirect_to :controller => 'admin', :action => 'projects' elsif !@project.new_record?
elsif !@project.new_record? # Project was created
# Project was created # But some objects were not copied due to validation failures
# But some objects were not copied due to validation failures # (eg. issues from disabled trackers)
# (eg. issues from disabled trackers) # TODO: inform about that
# TODO: inform about that redirect_to :controller => 'admin', :action => 'projects'
redirect_to :controller => 'admin', :action => 'projects'
end
end end
end end
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
@@ -322,9 +320,13 @@ class ProjectsController < ApplicationController
@issues_by_version = {} @issues_by_version = {}
unless @selected_tracker_ids.empty? unless @selected_tracker_ids.empty?
@versions.each do |version| @versions.each do |version|
conditions = {:tracker_id => @selected_tracker_ids}
if !@project.versions.include?(version)
conditions.merge!(:project_id => project_ids)
end
issues = version.fixed_issues.visible.find(:all, issues = version.fixed_issues.visible.find(:all,
:include => [:project, :status, :tracker, :priority], :include => [:project, :status, :tracker, :priority],
:conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, :conditions => conditions,
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
@issues_by_version[version] = issues @issues_by_version[version] = issues
end end
+1 -1
View File
@@ -74,7 +74,7 @@ private
def find_optional_project def find_optional_project
@project = Project.find(params[:project_id]) if params[:project_id] @project = Project.find(params[:project_id]) if params[:project_id]
render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) User.current.allowed_to?(:save_queries, @project, :global => true)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
+2 -2
View File
@@ -61,7 +61,7 @@ class ReportsController < ApplicationController
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
when "subproject" when "subproject"
@field = "project_id" @field = "project_id"
@rows = @project.descendants.visible @rows = @project.descendants.active
@data = issues_by_subproject @data = issues_by_subproject
@report_title = l(:field_subproject) @report_title = l(:field_subproject)
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
@@ -72,7 +72,7 @@ class ReportsController < ApplicationController
@categories = @project.issue_categories @categories = @project.issue_categories
@assignees = @project.members.collect { |m| m.user }.sort @assignees = @project.members.collect { |m| m.user }.sort
@authors = @project.members.collect { |m| m.user }.sort @authors = @project.members.collect { |m| m.user }.sort
@subprojects = @project.descendants.visible @subprojects = @project.descendants.active
issues_by_tracker issues_by_tracker
issues_by_version issues_by_version
issues_by_priority issues_by_priority
+5 -10
View File
@@ -25,9 +25,6 @@ class VersionsController < ApplicationController
helper :projects helper :projects
def show def show
@issues = @version.fixed_issues.visible.find(:all,
:include => [:status, :tracker, :priority],
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id")
end end
def edit def edit
@@ -49,13 +46,11 @@ class VersionsController < ApplicationController
end end
def destroy def destroy
if @version.fixed_issues.empty? @version.destroy
@version.destroy redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project rescue
else flash[:error] = l(:notice_unable_delete_version)
flash[:error] = l(:notice_unable_delete_version) redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end
end end
def status_by def status_by
+6 -6
View File
@@ -506,17 +506,17 @@ module ApplicationHelper
# Forum messages: # Forum messages:
# message#1218 -> Link to message with id 1218 # message#1218 -> Link to message with id 1218
text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m| text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m|
leading, esc, prefix, sep, identifier = $1, $2, $3, $5 || $7, $6 || $8 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
link = nil link = nil
if esc.nil? if esc.nil?
if prefix.nil? && sep == 'r' if prefix.nil? && sep == 'r'
if project && (changeset = project.changesets.find_by_revision(identifier)) if project && (changeset = project.changesets.find_by_revision(oid))
link = link_to("r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
:class => 'changeset', :class => 'changeset',
:title => truncate_single_line(changeset.comments, :length => 100)) :title => truncate_single_line(changeset.comments, :length => 100))
end end
elsif sep == '#' elsif sep == '#'
oid = identifier.to_i oid = oid.to_i
case prefix case prefix
when nil when nil
if issue = Issue.visible.find_by_id(oid, :include => :status) if issue = Issue.visible.find_by_id(oid, :include => :status)
@@ -547,7 +547,7 @@ module ApplicationHelper
end end
elsif sep == ':' elsif sep == ':'
# removes the double quotes if any # removes the double quotes if any
name = identifier.gsub(%r{^"(.*)"$}, "\\1") name = oid.gsub(%r{^"(.*)"$}, "\\1")
case prefix case prefix
when 'document' when 'document'
if project && document = project.documents.find_by_title(name) if project && document = project.documents.find_by_title(name)
@@ -584,7 +584,7 @@ module ApplicationHelper
end end
end end
end end
leading + (link || "#{prefix}#{sep}#{identifier}") leading + (link || "#{prefix}#{sep}#{oid}")
end end
text text
+14 -20
View File
@@ -52,19 +52,17 @@ module RepositoriesHelper
else else
change change
end end
end.compact end.compact
tree = { } tree = { }
changes.each do |change| changes.each do |change|
p = tree p = tree
dirs = change.path.to_s.split('/').select {|d| !d.blank?} dirs = change.path.to_s.split('/').select {|d| !d.blank?}
path = ''
dirs.each do |dir| dirs.each do |dir|
path += '/' + dir
p[:s] ||= {} p[:s] ||= {}
p = p[:s] p = p[:s]
p[path] ||= {} p[dir] ||= {}
p = p[path] p = p[dir]
end end
p[:c] = change p[:c] = change
end end
@@ -78,26 +76,21 @@ module RepositoriesHelper
output = '' output = ''
output << '<ul>' output << '<ul>'
tree.keys.sort.each do |file| tree.keys.sort.each do |file|
s = !tree[file][:s].nil?
c = tree[file][:c]
style = 'change' style = 'change'
text = File.basename(h(file)) style << ' folder' if s
if s = tree[file][:s] style << " change-#{c.action}" if c
style << ' folder'
path_param = to_path_param(@repository.relative_path(file)) text = h(file)
text = link_to(text, :controller => 'repositories', unless c.nil?
:action => 'show',
:id => @project,
:path => path_param,
:rev => @changeset.revision)
output << "<li class='#{style}'>#{text}</li>"
output << render_changes_tree(s)
elsif c = tree[file][:c]
style << " change-#{c.action}"
path_param = to_path_param(@repository.relative_path(c.path)) path_param = to_path_param(@repository.relative_path(c.path))
text = link_to(text, :controller => 'repositories', text = link_to(text, :controller => 'repositories',
:action => 'entry', :action => 'entry',
:id => @project, :id => @project,
:path => path_param, :path => path_param,
:rev => @changeset.revision) unless c.action == 'D' :rev => @changeset.revision) unless s || c.action == 'D'
text << " - #{c.revision}" unless c.revision.blank? text << " - #{c.revision}" unless c.revision.blank?
text << ' (' + link_to('diff', :controller => 'repositories', text << ' (' + link_to('diff', :controller => 'repositories',
:action => 'diff', :action => 'diff',
@@ -105,8 +98,9 @@ module RepositoriesHelper
:path => path_param, :path => path_param,
:rev => @changeset.revision) + ') ' if c.action == 'M' :rev => @changeset.revision) + ') ' if c.action == 'M'
text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank? text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank?
output << "<li class='#{style}'>#{text}</li>"
end end
output << "<li class='#{style}'>#{text}</li>"
output << render_changes_tree(tree[file][:s]) if s
end end
output << '</ul>' output << '</ul>'
output output
+9 -20
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # Redmine - project management software
# Copyright (C) 2006-2010 Jean-Philippe Lang # Copyright (C) 2006-2008 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -57,10 +57,6 @@ class Changeset < ActiveRecord::Base
super super
end end
def committer=(arg)
write_attribute(:committer, self.class.to_utf8(arg.to_s))
end
def project def project
repository.project repository.project
end end
@@ -84,6 +80,9 @@ class Changeset < ActiveRecord::Base
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
# keywords used to fix issues # keywords used to fix issues
fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip)
# status and optional done ratio applied
fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
done_ratio = Setting.commit_fix_done_ratio.blank? ? nil : Setting.commit_fix_done_ratio.to_i
kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|")
return if kw_regexp.blank? return if kw_regexp.blank?
@@ -101,7 +100,7 @@ class Changeset < ActiveRecord::Base
action = match[0] action = match[0]
target_issue_ids = match[1].scan(/\d+/) target_issue_ids = match[1].scan(/\d+/)
target_issues = find_referenced_issues_by_id(target_issue_ids) target_issues = find_referenced_issues_by_id(target_issue_ids)
if fix_keywords.include?(action.downcase) && fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id) if fix_status && fix_keywords.include?(action.downcase)
# update status of issues # update status of issues
logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug? logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
target_issues.each do |issue| target_issues.each do |issue|
@@ -115,9 +114,7 @@ class Changeset < ActiveRecord::Base
end end
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, csettext)) journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, csettext))
issue.status = fix_status issue.status = fix_status
unless Setting.commit_fix_done_ratio.blank? issue.done_ratio = done_ratio if done_ratio
issue.done_ratio = Setting.commit_fix_done_ratio.to_i
end
Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
{ :changeset => self, :issue => issue }) { :changeset => self, :issue => issue })
issue.save issue.save
@@ -126,8 +123,7 @@ class Changeset < ActiveRecord::Base
referenced_issues += target_issues referenced_issues += target_issues
end end
referenced_issues.uniq! self.issues = referenced_issues.uniq
self.issues = referenced_issues unless referenced_issues.empty?
end end
def short_comments def short_comments
@@ -158,7 +154,6 @@ class Changeset < ActiveRecord::Base
# Finds issues that can be referenced by the commit message # Finds issues that can be referenced by the commit message
# i.e. issues that belong to the repository project, a subproject or a parent project # i.e. issues that belong to the repository project, a subproject or a parent project
def find_referenced_issues_by_id(ids) def find_referenced_issues_by_id(ids)
return [] if ids.compact.empty?
Issue.find_all_by_id(ids, :include => :project).select {|issue| Issue.find_all_by_id(ids, :include => :project).select {|issue|
project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project) project == issue.project || project.is_ancestor_of?(issue.project) || project.is_descendant_of?(issue.project)
} }
@@ -176,17 +171,11 @@ class Changeset < ActiveRecord::Base
encoding = Setting.commit_logs_encoding.to_s.strip encoding = Setting.commit_logs_encoding.to_s.strip
unless encoding.blank? || encoding == 'UTF-8' unless encoding.blank? || encoding == 'UTF-8'
begin begin
str = Iconv.conv('UTF-8', encoding, str) return Iconv.conv('UTF-8', encoding, str)
rescue Iconv::Failure rescue Iconv::Failure
# do nothing here # do nothing here
end end
end end
# removes invalid UTF8 sequences str
begin
Iconv.conv('UTF-8//IGNORE', 'UTF-8', str + ' ')[0..-3]
rescue Iconv::InvalidEncoding
# "UTF-8//IGNORE" is not supported on some OS
str
end
end end
end end
+6 -23
View File
@@ -80,7 +80,7 @@ class Issue < ActiveRecord::Base
end end
def copy_from(arg) def copy_from(arg)
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg) issue = arg.is_a?(Issue) ? arg : Issue.find(arg)
self.attributes = issue.attributes.dup.except("id", "created_on", "updated_on") self.attributes = issue.attributes.dup.except("id", "created_on", "updated_on")
self.custom_values = issue.custom_values.collect {|v| v.clone} self.custom_values = issue.custom_values.collect {|v| v.clone}
self.status = issue.status self.status = issue.status
@@ -92,7 +92,7 @@ class Issue < ActiveRecord::Base
def move_to(new_project, new_tracker = nil, options = {}) def move_to(new_project, new_tracker = nil, options = {})
options ||= {} options ||= {}
issue = options[:copy] ? self.clone : self issue = options[:copy] ? self.clone : self
ret = Issue.transaction do transaction do
if new_project && issue.project_id != new_project.id if new_project && issue.project_id != new_project.id
# delete issue relations # delete issue relations
unless Setting.cross_project_issue_relations? unless Setting.cross_project_issue_relations?
@@ -129,12 +129,12 @@ class Issue < ActiveRecord::Base
# Manually update project_id on related time entries # Manually update project_id on related time entries
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id}) TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
end end
true
else else
raise ActiveRecord::Rollback Issue.connection.rollback_db_transaction
return false
end end
end end
ret ? issue : false return issue
end end
def priority_id=(pid) def priority_id=(pid)
@@ -159,8 +159,7 @@ class Issue < ActiveRecord::Base
end end
send :attributes_without_tracker_first=, new_attributes, *args send :attributes_without_tracker_first=, new_attributes, *args
end end
# Do not redefine alias chain on reload (see #4838) alias_method_chain :attributes=, :tracker_first
alias_method_chain(:attributes=, :tracker_first) unless method_defined?(:attributes_without_tracker_first=)
def estimated_hours=(h) def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
@@ -389,22 +388,6 @@ class Issue < ActiveRecord::Base
Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids]) Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids])
end end
# Returns an array of projects that current user can move issues to
def self.allowed_target_projects_on_move
projects = []
if User.current.admin?
# admin is allowed to move issues to any active (visible) project
projects = Project.visible.all
elsif User.current.logged?
if Role.non_member.allowed_to?(:move_issues)
projects = Project.visible.all
else
User.current.memberships.each {|m| projects << m.project if m.roles.detect {|r| r.allowed_to?(:move_issues)}}
end
end
projects
end
private private
# Update issues so their versions are not pointing to a # Update issues so their versions are not pointing to a
+1 -1
View File
@@ -49,7 +49,7 @@ class MailHandler < ActionMailer::Base
logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]" if logger && logger.info logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]" if logger && logger.info
return false return false
end end
@user = User.find_by_mail(sender_email) if sender_email.present? @user = User.find_by_mail(sender_email)
if @user && !@user.active? if @user && !@user.active?
logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]" if logger && logger.info logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]" if logger && logger.info
return false return false
+2 -11
View File
@@ -114,11 +114,11 @@ class Mailer < ActionMailer::Base
when 'Project' when 'Project'
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container) added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
added_to = "#{l(:label_project)}: #{container}" added_to = "#{l(:label_project)}: #{container}"
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
when 'Version' when 'Version'
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id) added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
added_to = "#{l(:label_version)}: #{container.name}" added_to = "#{l(:label_version)}: #{container.name}"
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
when 'Document' when 'Document'
added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id) added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
added_to = "#{l(:label_document)}: #{container.title}" added_to = "#{l(:label_document)}: #{container.title}"
@@ -311,15 +311,6 @@ class Mailer < ActionMailer::Base
end end
end end
# Activates/desactivates email deliveries during +block+
def self.with_deliveries(enabled = true, &block)
was_enabled = ActionMailer::Base.perform_deliveries
ActionMailer::Base.perform_deliveries = !!enabled
yield
ensure
ActionMailer::Base.perform_deliveries = was_enabled
end
private private
def initialize_defaults(method_name) def initialize_defaults(method_name)
super super
+1 -1
View File
@@ -16,7 +16,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Principal < ActiveRecord::Base class Principal < ActiveRecord::Base
set_table_name "#{table_name_prefix}users#{table_name_suffix}" set_table_name 'users'
has_many :members, :foreign_key => 'user_id', :dependent => :destroy has_many :members, :foreign_key => 'user_id', :dependent => :destroy
has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name" has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}", :order => "#{Project.table_name}.name"
+2 -14
View File
@@ -56,7 +56,7 @@ class Project < ActiveRecord::Base
:delete_permission => :manage_files :delete_permission => :manage_files
acts_as_customizable acts_as_customizable
acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil
acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"}, acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
:url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}}, :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}},
:author => nil :author => nil
@@ -249,7 +249,7 @@ class Project < ActiveRecord::Base
return @allowed_parents if @allowed_parents return @allowed_parents if @allowed_parents
@allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects)) @allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
@allowed_parents = @allowed_parents - self_and_descendants @allowed_parents = @allowed_parents - self_and_descendants
if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?) if User.current.allowed_to?(:add_project, nil, :global => true)
@allowed_parents << nil @allowed_parents << nil
end end
unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent) unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
@@ -512,23 +512,11 @@ class Project < ActiveRecord::Base
unless project.wiki.nil? unless project.wiki.nil?
self.wiki ||= Wiki.new self.wiki ||= Wiki.new
wiki.attributes = project.wiki.attributes.dup.except("id", "project_id") wiki.attributes = project.wiki.attributes.dup.except("id", "project_id")
wiki_pages_map = {}
project.wiki.pages.each do |page| project.wiki.pages.each do |page|
# Skip pages without content
next if page.content.nil?
new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on")) new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on"))
new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id")) new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id"))
new_wiki_page.content = new_wiki_content new_wiki_page.content = new_wiki_content
wiki.pages << new_wiki_page wiki.pages << new_wiki_page
wiki_pages_map[page.id] = new_wiki_page
end
wiki.save
# Reproduce page hierarchy
project.wiki.pages.each do |page|
if page.parent_id && wiki_pages_map[page.id]
wiki_pages_map[page.id].parent = wiki_pages_map[page.parent_id]
wiki_pages_map[page.id].save
end
end end
end end
end end
-4
View File
@@ -210,10 +210,6 @@ class Query < ActiveRecord::Base
add_custom_fields_filters(@project.all_issue_custom_fields) add_custom_fields_filters(@project.all_issue_custom_fields)
else else
# global filters for cross project issue list # global filters for cross project issue list
system_shared_versions = Version.visible.find_all_by_sharing('system')
unless system_shared_versions.empty?
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } }
end
add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true}))
end end
@available_filters @available_filters
+6 -17
View File
@@ -136,7 +136,6 @@ class Repository < ActiveRecord::Base
end end
end end
@committers = nil @committers = nil
@found_committer_users = nil
true true
else else
false false
@@ -147,34 +146,24 @@ class Repository < ActiveRecord::Base
# It will return nil if the committer is not yet mapped and if no User # It will return nil if the committer is not yet mapped and if no User
# with the same username or email was found # with the same username or email was found
def find_committer_user(committer) def find_committer_user(committer)
unless committer.blank? if committer
@found_committer_users ||= {}
return @found_committer_users[committer] if @found_committer_users.has_key?(committer)
user = nil
c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user)
if c && c.user if c && c.user
user = c.user c.user
elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
username, email = $1.strip, $3 username, email = $1.strip, $3
u = User.find_by_login(username) u = User.find_by_login(username)
u ||= User.find_by_mail(email) unless email.blank? u ||= User.find_by_mail(email) unless email.blank?
user = u u
end end
@found_committer_users[committer] = user
user
end end
end end
# Fetches new changesets for all repositories of active projects # fetch new changesets for all repositories
# Can be called periodically by an external script # can be called periodically by an external script
# eg. ruby script/runner "Repository.fetch_changesets" # eg. ruby script/runner "Repository.fetch_changesets"
def self.fetch_changesets def self.fetch_changesets
Project.active.has_module(:repository).find(:all, :include => :repository).each do |project| find(:all).each(&:fetch_changesets)
if project.repository
project.repository.fetch_changesets
end
end
end end
# scan changeset comments to find related and fixed issues for all repositories # scan changeset comments to find related and fixed issues for all repositories
+9 -12
View File
@@ -40,26 +40,23 @@ class Repository::Git < Repository
# With SCM's that have a sequential commit numbering, redmine is able to be # With SCM's that have a sequential commit numbering, redmine is able to be
# clever and only fetch changesets going forward from the most recent one # clever and only fetch changesets going forward from the most recent one
# it knows about. However, with git, you never know if people have merged # it knows about. However, with git, you never know if people have merged
# commits into the middle of the repository history, so we should parse # commits into the middle of the repository history, so we always have to
# the entire log. Since it's way too slow for large repositories, we only # parse the entire log.
# parse 1 week before the last known commit.
# The repository can still be fully reloaded by calling #clear_changesets
# before fetching changesets (eg. for offline resync)
def fetch_changesets def fetch_changesets
c = changesets.find(:first, :order => 'committed_on DESC') # Save ourselves an expensive operation if we're already up to date
since = (c ? c.committed_on - 7.days : nil) return if scm.num_revisions == changesets.count
revisions = scm.revisions('', nil, nil, :all => true, :since => since) revisions = scm.revisions('', nil, nil, :all => true)
return if revisions.nil? || revisions.empty? return if revisions.nil? || revisions.empty?
recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since]) # Find revisions that redmine knows about already
existing_revisions = changesets.find(:all).map!{|c| c.scmid}
# Clean out revisions that are no longer in git # Clean out revisions that are no longer in git
recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }} Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id])
# Subtract revisions that redmine already knows about # Subtract revisions that redmine already knows about
recent_revisions = recent_changesets.map{|c| c.scmid} revisions.reject!{|r| existing_revisions.include?(r.scmid)}
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
# Save the remaining ones to the database # Save the remaining ones to the database
revisions.each{|r| r.save(self)} unless revisions.nil? revisions.each{|r| r.save(self)} unless revisions.nil?
+8 -4
View File
@@ -1,5 +1,5 @@
# Redmine - project management software # redMine - project management software
# Copyright (C) 2006-2010 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,9 +16,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Version < ActiveRecord::Base class Version < ActiveRecord::Base
before_destroy :check_integrity
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'
acts_as_customizable acts_as_customizable
acts_as_attachable :view_permission => :view_files, acts_as_attachable :view_permission => :view_files,
:delete_permission => :manage_files :delete_permission => :manage_files
@@ -154,7 +155,10 @@ class Version < ActiveRecord::Base
end end
end end
private private
def check_integrity
raise "Can't delete version" if self.fixed_issues.find(:first)
end
# Update the issue's fixed versions. Used if a version's sharing changes. # Update the issue's fixed versions. Used if a version's sharing changes.
def update_issues_from_sharing_change def update_issues_from_sharing_change
-2
View File
@@ -1,4 +1,3 @@
<%= call_hook :view_account_login_top %>
<div id="login-form"> <div id="login-form">
<% form_tag({:action=> "login"}) do %> <% form_tag({:action=> "login"}) do %>
<%= back_url_hidden_field_tag %> <%= back_url_hidden_field_tag %>
@@ -39,4 +38,3 @@
<%= javascript_tag "Form.Element.focus('username');" %> <%= javascript_tag "Form.Element.focus('username');" %>
<% end %> <% end %>
</div> </div>
<%= call_hook :view_account_login_bottom %>
-4
View File
@@ -26,7 +26,3 @@
<% end %> <% end %>
<% html_title @document.title -%> <% html_title @document.title -%>
<% content_for :header_tags do %>
<%= stylesheet_link_tag 'scm' %>
<% end %>
+1 -1
View File
@@ -29,7 +29,7 @@
<% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %> <% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %>
<fieldset><legend><%=l(:label_user_new)%></legend> <fieldset><legend><%=l(:label_user_new)%></legend>
<p><%= text_field_tag 'user_search', nil %></p> <p><%= text_field_tag 'user_search', nil, :size => "40" %></p>
<%= observe_field(:user_search, <%= observe_field(:user_search,
:frequency => 0.5, :frequency => 0.5,
:update => :users, :update => :users,
+1 -1
View File
@@ -26,7 +26,7 @@
<% end %> <% end %>
<tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>"> <tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= issue.css_classes %>">
<td class="checkbox"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td> <td class="checkbox"><%= check_box_tag("ids[]", issue.id, false, :id => nil) %></td>
<td class="id"><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td> <td><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td>
<% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %> <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %>
</tr> </tr>
<% end -%> <% end -%>
+3 -1
View File
@@ -86,6 +86,7 @@ top = headers_height + 8
<%= link_to_issue i %> <%= link_to_issue i %>
<% else %> <% else %>
<span class="icon icon-package"> <span class="icon icon-package">
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i %> <%= link_to_version i %>
</span> </span>
<% end %> <% end %>
@@ -210,7 +211,8 @@ top = headers_height + 10
%> %>
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div> <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task"> <div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
<strong><%= format_version_name i %></strong> <%= h("#{i.project} -") unless @project && @project == i.project %>
<strong><%=h i %></strong>
</div> </div>
<% end %> <% end %>
<% top = top + 20 <% top = top + 20
+4 -4
View File
@@ -10,10 +10,10 @@
<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %> <% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
<%= hidden_field_tag('project_id', @project.to_param) if @project %> <%= hidden_field_tag('project_id', @project.to_param) if @project %>
<div id="query_form_content" class="hide-when-print"> <div id="query_form_content">
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>"> <fieldset id="filters" class="collapsible">
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend> <legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
<div style="<%= @query.new_record? ? "" : "display: none;" %>"> <div>
<%= render :partial => 'queries/filters', :locals => {:query => @query} %> <%= render :partial => 'queries/filters', :locals => {:query => @query} %>
</div> </div>
</fieldset> </fieldset>
@@ -33,7 +33,7 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
<p class="buttons hide-when-print"> <p class="buttons">
<%= link_to_remote l(:button_apply), <%= link_to_remote l(:button_apply),
{ :url => { :set_filter => 1 }, { :url => { :set_filter => 1 },
-2
View File
@@ -40,11 +40,9 @@
<h1><%= page_header_title %></h1> <h1><%= page_header_title %></h1>
<% if display_main_menu?(@project) %>
<div id="main-menu"> <div id="main-menu">
<%= render_main_menu(@project) %> <%= render_main_menu(@project) %>
</div> </div>
<% end %>
</div> </div>
<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %> <%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
+8 -8
View File
@@ -1,14 +1,14 @@
<h1><%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %></h1> <h1><%= link_to "#{issue.tracker.name} ##{issue.id}: #{issue.subject}", issue_url %></h1>
<ul> <ul>
<li><%=l(:field_author)%>: <%=h issue.author %></li> <li><%=l(:field_author)%>: <%= issue.author %></li>
<li><%=l(:field_status)%>: <%=h issue.status %></li> <li><%=l(:field_status)%>: <%= issue.status %></li>
<li><%=l(:field_priority)%>: <%=h issue.priority %></li> <li><%=l(:field_priority)%>: <%= issue.priority %></li>
<li><%=l(:field_assigned_to)%>: <%=h issue.assigned_to %></li> <li><%=l(:field_assigned_to)%>: <%= issue.assigned_to %></li>
<li><%=l(:field_category)%>: <%=h issue.category %></li> <li><%=l(:field_category)%>: <%= issue.category %></li>
<li><%=l(:field_fixed_version)%>: <%=h issue.fixed_version %></li> <li><%=l(:field_fixed_version)%>: <%= issue.fixed_version %></li>
<% issue.custom_values.each do |c| %> <% issue.custom_values.each do |c| %>
<li><%=h c.custom_field.name %>: <%=h show_value(c) %></li> <li><%= c.custom_field.name %>: <%= show_value(c) %></li>
<% end %> <% end %>
</ul> </ul>
@@ -1,2 +1,2 @@
<p><%= l(:mail_body_account_activation_request, h(@user.login)) %></p> <p><%= l(:mail_body_account_activation_request, @user.login) %></p>
<p><%= link_to @url, @url %></p> <p><%= link_to @url, @url %></p>
@@ -1,10 +1,10 @@
<% if @user.auth_source %> <% if @user.auth_source %>
<p><%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %></p> <p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p>
<% else %> <% else %>
<p><%= l(:mail_body_account_information) %>:</p> <p><%= l(:mail_body_account_information) %>:</p>
<ul> <ul>
<li><%= l(:field_login) %>: <%=h @user.login %></li> <li><%= l(:field_login) %>: <%= @user.login %></li>
<li><%= l(:field_password) %>: <%=h @password %></li> <li><%= l(:field_password) %>: <%= @password %></li>
</ul> </ul>
<% end %> <% end %>
@@ -1,5 +1,5 @@
<%= link_to @added_to, @added_to_url %><br /> <%= link_to @added_to, @added_to_url %><br />
<ul><% @attachments.each do |attachment | %> <ul><% @attachments.each do |attachment | %>
<li><%=h attachment.filename %></li> <li><%= attachment.filename %></li>
<% end %></ul> <% end %></ul>
@@ -1,3 +1,3 @@
<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)<br /> <%= link_to @document.title, @document_url %> (<%= @document.category.name %>)<br />
<br /> <br />
<%= textilizable(@document, :description, :only_path => false) %> <%= textilizable(@document, :description, :only_path => false) %>
+1 -1
View File
@@ -1,3 +1,3 @@
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %> <%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %>
<hr /> <hr />
<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %> <%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %>
+1 -1
View File
@@ -1,4 +1,4 @@
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> <%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %>
<ul> <ul>
<% for detail in @journal.details %> <% for detail in @journal.details %>
@@ -1,4 +1,4 @@
<p><%= l(:mail_body_lost_password) %><br /> <p><%= l(:mail_body_lost_password) %><br />
<%= auto_link(@url) %></p> <%= auto_link(@url) %></p>
<p><%= l(:field_login) %>: <b><%=h @token.user.login %></b></p> <p><%= l(:field_login) %>: <b><%= @token.user.login %></b></p>
@@ -1,4 +1,4 @@
<h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %></h1> <h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to @message.subject, @message_url %></h1>
<em><%=h @message.author %></em> <em><%= @message.author %></em>
<%= textilizable(@message, :content, :only_path => false) %> <%= textilizable(@message, :content, :only_path => false) %>
+2 -2
View File
@@ -1,4 +1,4 @@
<h1><%= link_to(h(@news.title), @news_url) %></h1> <h1><%= link_to @news.title, @news_url %></h1>
<em><%=h @news.author.name %></em> <em><%= @news.author.name %></em>
<%= textilizable(@news, :description, :only_path => false) %> <%= textilizable(@news, :description, :only_path => false) %>
+2 -2
View File
@@ -17,10 +17,10 @@
<% if Setting.rest_api_enabled? %> <% if Setting.rest_api_enabled? %>
<h4><%= l(:label_api_access_key) %></h4> <h4><%= l(:label_api_access_key) %></h4>
<div> <p>
<%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%>
<pre id='api-access-key' class='autoscroll'><%= @user.api_key %></pre> <pre id='api-access-key' class='autoscroll'><%= @user.api_key %></pre>
</div> </p>
<%= javascript_tag("$('api-access-key').hide();") %> <%= javascript_tag("$('api-access-key').hide();") %>
<p> <p>
<% if @user.api_token %> <% if @user.api_token %>
-2
View File
@@ -21,8 +21,6 @@
<label class="block"><%= check_box_tag 'only[]', 'boards', true %> <%= l(:label_board_plural) %> (<%= @source_project.boards.count %>)</label> <label class="block"><%= check_box_tag 'only[]', 'boards', true %> <%= l(:label_board_plural) %> (<%= @source_project.boards.count %>)</label>
<label class="block"><%= check_box_tag 'only[]', 'wiki', true %> <%= l(:label_wiki_page_plural) %> (<%= @source_project.wiki.nil? ? 0 : @source_project.wiki.pages.count %>)</label> <label class="block"><%= check_box_tag 'only[]', 'wiki', true %> <%= l(:label_wiki_page_plural) %> (<%= @source_project.wiki.nil? ? 0 : @source_project.wiki.pages.count %>)</label>
<%= hidden_field_tag 'only[]', '' %> <%= hidden_field_tag 'only[]', '' %>
<br />
<label class="block"><%= check_box_tag 'notifications', 1, params[:notifications] %> <%= l(:label_project_copy_notifications) %></label>
</fieldset> </fieldset>
<%= submit_tag l(:button_copy) %> <%= submit_tag l(:button_copy) %>
-4
View File
@@ -1,7 +1,3 @@
<% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %>
<% end %>
<div class="contextual"> <div class="contextual">
<%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'}, :class => 'icon icon-add') + ' |' if User.current.allowed_to?(:add_project, nil, :global => true) %> <%= link_to(l(:label_project_new), {:controller => 'projects', :action => 'add'}, :class => 'icon icon-add') + ' |' if User.current.allowed_to?(:add_project, nil, :global => true) %>
<%= link_to(l(:label_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %> <%= link_to(l(:label_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %>
+1 -1
View File
@@ -58,7 +58,7 @@
<% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %> <% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %>
<fieldset><legend><%=l(:label_member_new)%></legend> <fieldset><legend><%=l(:label_member_new)%></legend>
<p><%= text_field_tag 'principal_search', nil %></p> <p><%= text_field_tag 'principal_search', nil, :size => "40" %></p>
<%= observe_field(:principal_search, <%= observe_field(:principal_search,
:frequency => 0.5, :frequency => 0.5,
:update => :principals, :update => :principals,
+2 -4
View File
@@ -7,11 +7,9 @@
<h2><%=l(:label_overview)%></h2> <h2><%=l(:label_overview)%></h2>
<div class="splitcontentleft"> <div class="splitcontentleft">
<div class="wiki"> <%= textilizable @project.description %>
<%= textilizable @project.description %>
</div>
<ul> <ul>
<% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %></li><% end %> <% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= link_to(h(@project.homepage), @project.homepage) %></li><% end %>
<% if @subprojects.any? %> <% if @subprojects.any? %>
<li><%=l(:label_subproject_plural)%>: <li><%=l(:label_subproject_plural)%>:
<%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li> <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li>
+1 -1
View File
@@ -16,6 +16,6 @@ dirs.each do |dir|
/ <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> / <%= link_to h(filename), :action => 'changes', :id => @project, :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %>
<% end %> <% end %>
<%= "@ #{h revision}" if revision %> <%= "@ #{revision}" if revision %>
<% html_title(with_leading_slash(path)) -%> <% html_title(with_leading_slash(path)) -%>
+5 -2
View File
@@ -32,10 +32,13 @@
<%= render :partial => 'versions/overview', :locals => {:version => @version} %> <%= render :partial => 'versions/overview', :locals => {:version => @version} %>
<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> <%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
<% if @issues.present? %> <% issues = @version.fixed_issues.find(:all,
:include => [:status, :tracker, :priority],
:order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") %>
<% if issues.size > 0 %>
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend> <fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
<ul> <ul>
<% @issues.each do |issue| -%> <% issues.each do |issue| -%>
<li><%= link_to_issue(issue) %></li> <li><%= link_to_issue(issue) %></li>
<% end -%> <% end -%>
</ul> </ul>
+1 -67
View File
@@ -1,70 +1,4 @@
# = Outgoing email settings # Outgoing email settings
#
# Each environment has it's own configuration options. If you are only
# running in production, only the production block needs to be configured.
#
# == Common configurations
#
# === Sendmail command
#
# production:
# delivery_method: :sendmail
#
# === Simple SMTP server at localhost
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "localhost"
# port: 25
#
# === SMTP server at example.com using LOGIN authentication and checking HELO for foo.com
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "example.com"
# port: 25
# authentication: :login
# domain: 'foo.com'
# user_name: 'myaccount'
# password: 'password'
#
# === SMTP server at example.com using PLAIN authentication
#
# production:
# delivery_method: :smtp
# smtp_settings:
# address: "example.com"
# port: 25
# authentication: :plain
# domain: 'example.com'
# user_name: 'myaccount'
# password: 'password'
#
# === SMTP server at using TLS (GMail)
#
# This requires some additional configuration. See the article at:
# http://redmineblog.com/articles/setup-redmine-to-send-email-using-gmail/
#
# production:
# delivery_method: :smtp
# smtp_settings:
# tls: true
# address: "smtp.gmail.com"
# port: 587
# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps
# authentication: :plain
# user_name: "your_email@gmail.com"
# password: "your_password"
#
#
# == More configuration options
#
# See the "Configuration options" at the following website for a list of the
# full options allowed:
#
# http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer
production: production:
delivery_method: :smtp delivery_method: :smtp
+1 -1
View File
@@ -25,5 +25,5 @@ config.action_controller.session = {
config.action_controller.allow_forgery_protection = false config.action_controller.allow_forgery_protection = false
config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com" config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
config.gem "edavis10-object_daddy", :lib => "object_daddy" config.gem "nofxx-object_daddy", :lib => "object_daddy", :source => "http://gems.github.com"
config.gem "mocha" config.gem "mocha"
+29 -1
View File
@@ -1 +1,29 @@
instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb')) # Settings specified here will take precedence over those in config/environment.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_mailer.perform_deliveries = true
config.action_mailer.delivery_method = :test
config.action_controller.session = {
:session_key => "_test_session",
:secret => "some secret phrase for the tests."
}
# Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application
config.action_controller.allow_forgery_protection = false
config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
config.gem "nofxx-object_daddy", :lib => "object_daddy", :source => "http://gems.github.com"
config.gem "mocha"
+29 -1
View File
@@ -1 +1,29 @@
instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb')) # Settings specified here will take precedence over those in config/environment.rb
# The test environment is used exclusively to run your application's
# test suite. You never need to work with it otherwise. Remember that
# your test database is "scratch space" for the test suite and is wiped
# and recreated between test runs. Don't rely on the data there!
config.cache_classes = true
# Log error messages when you accidentally call methods on nil.
config.whiny_nils = true
# Show full error reports and disable caching
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_mailer.perform_deliveries = true
config.action_mailer.delivery_method = :test
config.action_controller.session = {
:session_key => "_test_session",
:secret => "some secret phrase for the tests."
}
# Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application
config.action_controller.allow_forgery_protection = false
config.gem "thoughtbot-shoulda", :lib => "shoulda", :source => "http://gems.github.com"
config.gem "nofxx-object_daddy", :lib => "object_daddy", :source => "http://gems.github.com"
config.gem "mocha"
+1 -1
View File
@@ -881,4 +881,4 @@ bg:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -905,4 +905,3 @@ bs:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -884,4 +884,3 @@ ca:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -887,4 +887,3 @@ cs:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -907,4 +907,3 @@ da:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -907,4 +907,3 @@ de:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -887,4 +887,3 @@ el:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -748,7 +748,6 @@ en:
label_api_access_key: API access key label_api_access_key: API access key
label_missing_api_access_key: Missing an API access key label_missing_api_access_key: Missing an API access key
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_project_copy_notifications: Send email notifications during the project copy
button_login: Login button_login: Login
button_submit: Submit button_submit: Submit
-1
View File
@@ -931,4 +931,3 @@ es:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -917,4 +917,3 @@ fi:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
+2 -3
View File
@@ -764,7 +764,6 @@ fr:
label_missing_feeds_access_key: Clé d'accès RSS manquante label_missing_feeds_access_key: Clé d'accès RSS manquante
label_close_versions: Fermer les versions terminées label_close_versions: Fermer les versions terminées
label_revision_id: Revision {{value}} label_revision_id: Revision {{value}}
label_project_copy_notifications: Envoyer les notifications durant la copie du projet
button_login: Connexion button_login: Connexion
button_submit: Soumettre button_submit: Soumettre
@@ -812,10 +811,10 @@ fr:
status_active: actif status_active: actif
status_registered: enregistré status_registered: enregistré
status_locked: verrouillé status_locked: vérouillé
version_status_open: ouvert version_status_open: ouvert
version_status_locked: verrouillé version_status_locked: vérouillé
version_status_closed: fermé version_status_closed: fermé
text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée
-1
View File
@@ -907,4 +907,3 @@ gl:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -891,4 +891,3 @@ he:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -894,4 +894,3 @@ hr:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -912,4 +912,3 @@
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -899,4 +899,3 @@ id:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
+1 -1
View File
@@ -894,4 +894,4 @@ it:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -916,4 +916,3 @@ ja:
enumeration_activities: 作業分類 (時間トラッキング) enumeration_activities: 作業分類 (時間トラッキング)
enumeration_system_activity: システム作業分類 enumeration_system_activity: システム作業分類
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -947,4 +947,3 @@ ko:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -955,4 +955,3 @@ lt:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -869,4 +869,3 @@ nl:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -882,4 +882,3 @@
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -912,4 +912,3 @@ pl:
permission_export_wiki_pages: Eksport stron wiki permission_export_wiki_pages: Eksport stron wiki
permission_manage_project_activities: Zarządzanie aktywnościami projektu permission_manage_project_activities: Zarządzanie aktywnościami projektu
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -915,4 +915,3 @@ pt-BR:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -899,4 +899,3 @@ pt:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -884,4 +884,3 @@ ro:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -995,4 +995,3 @@ ru:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -886,4 +886,3 @@ sk:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -883,4 +883,3 @@ sl:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -902,4 +902,3 @@
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -936,4 +936,3 @@ sv:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -884,4 +884,3 @@ th:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -914,4 +914,3 @@ tr:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -883,4 +883,3 @@ uk:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -946,4 +946,3 @@ vi:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
-1
View File
@@ -978,4 +978,3 @@
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
+1 -1
View File
@@ -909,4 +909,4 @@ zh:
permission_export_wiki_pages: Export wiki pages permission_export_wiki_pages: Export wiki pages
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Cache formatted text
permission_manage_project_activities: Manage project activities permission_manage_project_activities: Manage project activities
label_project_copy_notifications: Send email notifications during the project copy
@@ -1,9 +0,0 @@
class AddIndexOnChangesetsScmid < ActiveRecord::Migration
def self.up
add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid
end
def self.down
remove_index :changesets, :name => :changesets_repos_scmid
end
end
-76
View File
@@ -4,82 +4,6 @@ Redmine - project management software
Copyright (C) 2006-2010 Jean-Philippe Lang Copyright (C) 2006-2010 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== v1.0.0
Adds context menu to the roadmap issue lists
== 2010-07-07 v0.9.6
Fixed: Redmine.pm access by unauthorized users
== 2010-06-24 v0.9.5
Linkify folder names on revision view
"fiters" and "options" should be hidden in print view via css
Fixed: NoMethodError when no issue params are submitted
Fixed: projects.atom with required authentication
Fixed: External links not correctly displayed in Wiki TOC
Fixed: Member role forms in project settings are not hidden after member added
Fixed: pre can't be inside p
Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT
Fixed: mail handler fails when the from address is empty
== 2010-05-01 v0.9.4
Filters collapsed by default on issues index page for a saved query
Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
Fixed: remove "main-menu" div when the menu is empty
Fixed: Code syntax highlighting not working in Document page
Fixed: Git blame/annotate fails on moved files
Fixed: Failing test in test_show_atom
Fixed: Migrate from trac - not displayed Wikis
Fixed: Email notifications on file upload sent to empty recipient list
Fixed: Migrating from trac is not possible, fails to allocate memory
Fixed: Lost password no longer flashes a confirmation message
Fixed: Crash while deleting in-use enumeration
Fixed: Hard coded English string at the selection of issue watchers
Fixed: Bazaar v2.1.0 changed behaviour
Fixed: Roadmap display can raise an exception if no trackers are selected
Fixed: Gravatar breaks layout of "logged in" page
Fixed: Reposman.rb on Windows
Fixed: Possible error 500 while moving an issue to another project with SQLite
Fixed: backslashes in issue description/note should be escaped when quoted
Fixed: Long text in <pre> disrupts Associated revisions
Fixed: Links to missing wiki pages not red on project overview page
Fixed: Cannot delete a project with subprojects that shares versions
Fixed: Update of Subversion changesets broken under Solaris
Fixed: "Move issues" permission not working for Non member
Fixed: Sidebar overlap on Users tab of Group editor
Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
Fixed: Report shows sub-projects for non-members
Fixed: 500 internal error when browsing any Redmine page in epiphany
Fixed: Watchers selection lost when issue creation fails
Fixed: When copying projects, redmine should not generate an email to people who created issues
Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
Fixed: Plugin generators should display help if no parameter is given
== 2010-02-28 v0.9.3
Adds filter for system shared versions on the cross project issue list
Makes project identifiers searchable
Remove invalid utf8 sequences from commit comments and author name
Fixed: Wrong link when "http" not included in project "Homepage" link
Fixed: Escaping in html email templates
Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
Fixed: Deselecting textile text formatting causes interning empty string errors
Fixed: error with postgres when entering a non-numeric id for an issue relation
Fixed: div.task incorrectly wrapping on Gantt Chart
Fixed: Project copy loses wiki pages hierarchy
Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
Fixed: Duplicated project name for subproject version on gantt chart
Fixed: roadmap shows subprojects issues even if subprojects is unchecked
Fixed: IndexError if all the :last menu items are deleted from a menu
Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
== 2010-02-07 v0.9.2 == 2010-02-07 v0.9.2
* Fixed: Sub-project repository commits not displayed on parent project issues * Fixed: Sub-project repository commits not displayed on parent project issues
+7 -11
View File
@@ -7,11 +7,7 @@ http://www.redmine.org/
== Requirements == Requirements
* Ruby 1.8.6 or 1.8.7 * Ruby on Rails 2.3.5
* Ruby on Rails 2.3.5 (official downloadable Redmine releases are packaged with
the appropriate Rails version)
* A database: * A database:
* MySQL (tested with MySQL 5) * MySQL (tested with MySQL 5)
* PostgreSQL (tested with PostgreSQL 8.1) * PostgreSQL (tested with PostgreSQL 8.1)
@@ -30,15 +26,15 @@ Optional:
3. Configure database parameters in config/database.yml 3. Configure database parameters in config/database.yml
for "production" environment (default database is MySQL) for "production" environment (default database is MySQL)
4. Generate a session store secret 4. Create the database structure. Under the application main directory:
Redmine stores session data in cookies by default, which requires
a secret to be generated. Run:
rake generate_session_store
5. Create the database structure. Under the application main directory:
rake db:migrate RAILS_ENV="production" rake db:migrate RAILS_ENV="production"
It will create tables and an administrator account. It will create tables and an administrator account.
5. Generate a session store secret
Redmine stores session data in cookies by default, which requires
a secret to be generated. Run:
rake config/initializers/session_store.rb
6. Setting up permissions 6. Setting up permissions
The user who runs Redmine must have write permission on the following The user who runs Redmine must have write permission on the following
subdirectories: files, log, tmp (create the last one if not present). subdirectories: files, log, tmp (create the last one if not present).
+8 -8
View File
@@ -12,19 +12,19 @@ http://www.redmine.org/
2. Copy your database settings (RAILS_ROOT/config/database.yml) 2. Copy your database settings (RAILS_ROOT/config/database.yml)
and SMTP settings (RAILS_ROOT/config/email.yml) and SMTP settings (RAILS_ROOT/config/email.yml)
into the new config directory into the new config directory
DO NOT REPLACE OR EDIT ANY OTHER FILES. DO NOT REPLACE ANY OTHERS FILES.
3. Generate a session store secret 3. Migrate your database (please make a backup before doing this):
Redmine stores session data in cookies by default, which requires
a secret to be generated. Run:
rake generate_session_store
4. Migrate your database (please make a backup before doing this):
rake db:migrate RAILS_ENV="production" rake db:migrate RAILS_ENV="production"
5. Copy the RAILS_ROOT/files directory content into your new installation 4. Copy the RAILS_ROOT/files directory content into your new installation
This directory contains all the attached files This directory contains all the attached files
5. Generate a session store secret
Redmine stores session data in cookies by default, which requires
a secret to be generated. Run:
rake config/initializers/session_store.rb
== Notes == Notes
1. Rails 2.3.5 is required for version 0.9. 1. Rails 2.3.5 is required for version 0.9.
+1 -32
View File
@@ -227,39 +227,10 @@ sub authen_handler {
} }
} }
# check if authentication is forced
sub is_authentication_forced {
my $r = shift;
my $dbh = connect_database($r);
my $sth = $dbh->prepare(
"SELECT value FROM settings where settings.name = 'login_required';"
);
$sth->execute();
my $ret = 0;
if (my @row = $sth->fetchrow_array) {
if ($row[0] eq "1" || $row[0] eq "t") {
$ret = 1;
}
}
$sth->finish();
undef $sth;
$dbh->disconnect();
undef $dbh;
$ret;
}
sub is_public_project { sub is_public_project {
my $project_id = shift; my $project_id = shift;
my $r = shift; my $r = shift;
if (is_authentication_forced($r)) {
return 0;
}
my $dbh = connect_database($r); my $dbh = connect_database($r);
my $sth = $dbh->prepare( my $sth = $dbh->prepare(
"SELECT is_public FROM projects WHERE projects.identifier = ?;" "SELECT is_public FROM projects WHERE projects.identifier = ?;"
@@ -338,9 +309,7 @@ sub is_member {
bindpw => $rowldap[4] ? $rowldap[4] : "", bindpw => $rowldap[4] ? $rowldap[4] : "",
filter => "(".$rowldap[6]."=%s)" filter => "(".$rowldap[6]."=%s)"
); );
my $method = $r->method; $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
} }
$sthldap->finish(); $sthldap->finish();
undef $sthldap; undef $sthldap;
+1 -5
View File
@@ -221,15 +221,11 @@ def other_read_right?(file)
end end
def owner_name(file) def owner_name(file)
mswin? ? RUBY_PLATFORM =~ /mswin/ ?
$svn_owner : $svn_owner :
Etc.getpwuid( File.stat(file).uid ).name Etc.getpwuid( File.stat(file).uid ).name
end end
def mswin?
(RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)
end
projects.each do |project| projects.each do |project|
log("treating project #{project.name}", :level => 1) log("treating project #{project.name}", :level => 1)
@@ -6,7 +6,6 @@ class RedminePluginControllerGenerator < ControllerGenerator
def initialize(runtime_args, runtime_options = {}) def initialize(runtime_args, runtime_options = {})
runtime_args = runtime_args.dup runtime_args = runtime_args.dup
usage if runtime_args.empty?
@plugin_name = "redmine_" + runtime_args.shift.underscore @plugin_name = "redmine_" + runtime_args.shift.underscore
@plugin_pretty_name = plugin_name.titleize @plugin_pretty_name = plugin_name.titleize
@plugin_path = "vendor/plugins/#{plugin_name}" @plugin_path = "vendor/plugins/#{plugin_name}"
@@ -6,7 +6,6 @@ class RedminePluginModelGenerator < ModelGenerator
def initialize(runtime_args, runtime_options = {}) def initialize(runtime_args, runtime_options = {})
runtime_args = runtime_args.dup runtime_args = runtime_args.dup
usage if runtime_args.empty?
@plugin_name = "redmine_" + runtime_args.shift.underscore @plugin_name = "redmine_" + runtime_args.shift.underscore
@plugin_pretty_name = plugin_name.titleize @plugin_pretty_name = plugin_name.titleize
@plugin_path = "vendor/plugins/#{plugin_name}" @plugin_path = "vendor/plugins/#{plugin_name}"
+1 -1
View File
@@ -818,7 +818,7 @@ class RedCloth3 < String
post = ")"+post # add closing parenth to post post = ")"+post # add closing parenth to post
end end
atts = pba( atts ) atts = pba( atts )
atts = " href=\"#{ htmlesc url }#{ slash }\"#{ atts }" atts = " href=\"#{ url }#{ slash }\"#{ atts }"
atts << " title=\"#{ htmlesc title }\"" if title atts << " title=\"#{ htmlesc title }\"" if title
atts = shelve( atts ) if atts atts = shelve( atts ) if atts
+2 -16
View File
@@ -84,14 +84,6 @@ module TreeNodePatch
end end
# Wrapp remove! making sure to decrement the last_items counter if
# the removed child was a last item
def remove!(child)
@last_items_count -= +1 if child && child.last
super
end
# Will return the position (zero-based) of the current child in # Will return the position (zero-based) of the current child in
# it's parent # it's parent
def position def position
@@ -166,11 +158,6 @@ module Redmine
render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project) render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
end end
def display_main_menu?(project)
menu_name = project && !project.new_record? ? :project_menu : :application_menu
Redmine::MenuManager.items(menu_name).size > 1 # 1 element is the root
end
def render_menu(menu, project=nil) def render_menu(menu, project=nil)
links = [] links = []
menu_items_for(menu, project) do |node| menu_items_for(menu, project) do |node|
@@ -365,7 +352,7 @@ module Redmine
target_root.add(MenuItem.new(name, url, options)) target_root.add(MenuItem.new(name, url, options))
end end
elsif options[:last] # don't delete, needs to be stored elsif options.delete(:last)
target_root.add_last(MenuItem.new(name, url, options)) target_root.add_last(MenuItem.new(name, url, options))
else else
target_root.add(MenuItem.new(name, url, options)) target_root.add(MenuItem.new(name, url, options))
@@ -399,7 +386,7 @@ module Redmine
class MenuItem < Tree::TreeNode class MenuItem < Tree::TreeNode
include Redmine::I18n include Redmine::I18n
attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last attr_reader :name, :url, :param, :condition, :parent, :child_menus
def initialize(name, url, options) def initialize(name, url, options)
raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
@@ -416,7 +403,6 @@ module Redmine
@html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
@parent = options[:parent] @parent = options[:parent]
@child_menus = options[:children] @child_menus = options[:children]
@last = options[:last] || false
super @name.to_sym super @name.to_sym
end end
+7 -9
View File
@@ -286,8 +286,8 @@ module Redmine
end end
def save(repo) def save(repo)
Changeset.transaction do if repo.changesets.find_by_scmid(scmid.to_s).nil?
changeset = Changeset.new( changeset = Changeset.create!(
:repository => repo, :repository => repo,
:revision => identifier, :revision => identifier,
:scmid => scmid, :scmid => scmid,
@@ -295,13 +295,11 @@ module Redmine
:committed_on => time, :committed_on => time,
:comments => message) :comments => message)
if changeset.save paths.each do |file|
paths.each do |file| Change.create!(
Change.create( :changeset => changeset,
:changeset => changeset, :action => file[:action],
:action => file[:action], :path => file[:path])
:path => file[:path])
end
end end
end end
end end
+5 -5
View File
@@ -56,14 +56,14 @@ module Redmine
shellout(cmd) do |io| shellout(cmd) do |io|
prefix = "#{url}/#{path}".gsub('\\', '/') prefix = "#{url}/#{path}".gsub('\\', '/')
logger.debug "PREFIX: #{prefix}" logger.debug "PREFIX: #{prefix}"
re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)$} re = %r{^V\s+#{Regexp.escape(prefix)}(\/?)([^\/]+)(\/?)\s+(\S+)$}
io.each_line do |line| io.each_line do |line|
next unless line =~ re next unless line =~ re
entries << Entry.new({:name => $3.strip, entries << Entry.new({:name => $2.strip,
:path => ((path.empty? ? "" : "#{path}/") + $3.strip), :path => ((path.empty? ? "" : "#{path}/") + $2.strip),
:kind => ($4.blank? ? 'file' : 'dir'), :kind => ($3.blank? ? 'file' : 'dir'),
:size => nil, :size => nil,
:lastrev => Revision.new(:revision => $5.strip) :lastrev => Revision.new(:revision => $4.strip)
}) })
end end
end end
+14 -21
View File
@@ -33,22 +33,21 @@ module Redmine
end end
def branches def branches
return @branches if @branches branches = []
@branches = []
cmd = "#{GIT_BIN} --git-dir #{target('')} branch" cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line do |line| io.each_line do |line|
@branches << line.match('\s*\*?\s*(.*)$')[1] branches << line.match('\s*\*?\s*(.*)$')[1]
end end
end end
@branches.sort! branches.sort!
end end
def tags def tags
return @tags if @tags tags = []
cmd = "#{GIT_BIN} --git-dir #{target('')} tag" cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
shellout(cmd) do |io| shellout(cmd) do |io|
@tags = io.readlines.sort!.map{|t| t.strip} io.readlines.sort!.map{|t| t.strip}
end end
end end
@@ -111,16 +110,20 @@ module Redmine
end end
end end
def num_revisions
cmd = "#{GIT_BIN} --git-dir #{target('')} log --all --pretty=format:'' | wc -l"
shellout(cmd) {|io| io.gets.chomp.to_i + 1}
end
def revisions(path, identifier_from, identifier_to, options={}) def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller" cmd = "#{GIT_BIN} --git-dir #{target('')} log --find-copies-harder --raw --date=iso --pretty=fuller"
cmd << " --reverse" if options[:reverse] cmd << " --reverse" if options[:reverse]
cmd << " --all" if options[:all] cmd << " --all" if options[:all]
cmd << " -n #{options[:limit]} " if options[:limit] cmd << " -n #{options[:limit]} " if options[:limit]
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
cmd << " #{shell_quote identifier_to} " if identifier_to cmd << " #{shell_quote identifier_to} " if identifier_to
cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since]
cmd << " -- #{path}" if path && !path.empty? cmd << " -- #{path}" if path && !path.empty?
shellout(cmd) do |io| shellout(cmd) do |io|
@@ -227,26 +230,16 @@ module Redmine
def annotate(path, identifier=nil) def annotate(path, identifier=nil)
identifier = 'HEAD' if identifier.blank? identifier = 'HEAD' if identifier.blank?
cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}" cmd = "#{GIT_BIN} --git-dir #{target('')} blame -l #{shell_quote identifier} -- #{shell_quote path}"
blame = Annotate.new blame = Annotate.new
content = nil content = nil
shellout(cmd) { |io| io.binmode; content = io.read } shellout(cmd) { |io| io.binmode; content = io.read }
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
# git annotates binary files # git annotates binary files
return nil if content.is_binary_data? return nil if content.is_binary_data?
identifier = ''
# git shows commit author on the first occurrence only
authors_by_commit = {}
content.split("\n").each do |line| content.split("\n").each do |line|
if line =~ /^([0-9a-f]{39,40})\s.*/ next unless line =~ /([0-9a-f]{39,40})\s\((\w*)[^\)]*\)(.*)/
identifier = $1 blame.add_line($3.rstrip, Revision.new(:identifier => $1, :author => $2.strip))
elsif line =~ /^author (.+)/
authors_by_commit[identifier] = $1.strip
elsif line =~ /^\t(.*)/
blame.add_line($1, Revision.new(:identifier => identifier, :author => authors_by_commit[identifier]))
identifier = ''
author = ''
end
end end
blame blame
end end

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