Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43eb3ed51c | ||
|
|
a146c2d03f | ||
|
|
a62ff0841f | ||
|
|
d7ec02691f | ||
|
|
e7790bb6b5 | ||
|
|
34f73b005b | ||
|
|
ba42e1e2ff | ||
|
|
14074da8b1 | ||
|
|
44851d079f | ||
|
|
e6d053c3fd | ||
|
|
f17924c60d | ||
|
|
90e23e4d5d | ||
|
|
88a2792778 | ||
|
|
4c881d54a7 | ||
|
|
a6d45cc68f | ||
|
|
f58f7e0e41 | ||
|
|
473366f887 | ||
|
|
f6d2a4c29f | ||
|
|
b26d0fe041 | ||
|
|
98f3e98d82 | ||
|
|
7b27280c9b | ||
|
|
d287436627 | ||
|
|
666d3d6472 | ||
|
|
36063f16ee | ||
|
|
4a295e723e | ||
|
|
6e67d76194 | ||
|
|
eb55efd604 | ||
|
|
390eb7849c | ||
|
|
1588f3f6dc | ||
|
|
5ef8e8d45f | ||
|
|
cd15eb77d9 | ||
|
|
3b699806d9 | ||
|
|
d2367ccf53 | ||
|
|
9c00b8aa21 | ||
|
|
bbb00b0bc4 | ||
|
|
feac751318 | ||
|
|
eb4a7f9f2e | ||
|
|
7ce9ba9e28 | ||
|
|
53880a4e08 | ||
|
|
f92aa00705 | ||
|
|
b240da3833 | ||
|
|
da8624f7c7 | ||
|
|
46be83cd5e | ||
|
|
667f7927a7 | ||
|
|
3e6f42e46d | ||
|
|
30c45a6187 | ||
|
|
32288ed5d7 | ||
|
|
beb89eb8bb | ||
|
|
62d8016c4f | ||
|
|
5a7a3b2392 | ||
|
|
a2ad66a5c0 | ||
|
|
bfd9164c0a | ||
|
|
d80fb751fd | ||
|
|
aacabbe645 | ||
|
|
8eafcbede9 | ||
|
|
43c1481998 | ||
|
|
17f60af490 | ||
|
|
e5e5ad6b7a | ||
|
|
13fb739b56 | ||
|
|
73e849be58 | ||
|
|
0b7d4e818a | ||
|
|
40a4b111fa | ||
|
|
7d913f93c3 | ||
|
|
864fd9c6a1 | ||
|
|
57dcbd7376 | ||
|
|
0ef11ef4fe |
@@ -25,8 +25,7 @@ class AccountController < ApplicationController
|
||||
# Login request and validation
|
||||
def login
|
||||
if request.get?
|
||||
# Logout user
|
||||
self.logged_user = nil
|
||||
logout_user
|
||||
else
|
||||
# Authenticate user
|
||||
if Setting.openid? && using_open_id?
|
||||
@@ -39,9 +38,7 @@ class AccountController < ApplicationController
|
||||
|
||||
# Log out current user and redirect to welcome page
|
||||
def logout
|
||||
cookies.delete :autologin
|
||||
Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) if User.current.logged?
|
||||
self.logged_user = nil
|
||||
logout_user
|
||||
redirect_to home_url
|
||||
end
|
||||
|
||||
@@ -134,7 +131,15 @@ class AccountController < ApplicationController
|
||||
end
|
||||
|
||||
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
|
||||
user = User.try_to_login(params[:username], params[:password])
|
||||
|
||||
|
||||
@@ -107,8 +107,9 @@ class ApplicationController < ActionController::Base
|
||||
lang = find_language(User.current.language)
|
||||
end
|
||||
if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE']
|
||||
accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.downcase
|
||||
accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first
|
||||
if !accept_lang.blank?
|
||||
accept_lang = accept_lang.downcase
|
||||
lang = find_language(accept_lang) || find_language(accept_lang.split('-').first)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -76,12 +76,12 @@ class EnumerationsController < ApplicationController
|
||||
@enumeration.destroy
|
||||
redirect_to :action => 'index'
|
||||
elsif params[:reassign_to_id]
|
||||
if reassign_to = Enumeration.find_by_type_and_id(@enumeration.type, params[:reassign_to_id])
|
||||
if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id])
|
||||
@enumeration.destroy(reassign_to)
|
||||
redirect_to :action => 'index'
|
||||
end
|
||||
end
|
||||
@enumerations = Enumeration.find(:all, :conditions => ['type = (?)', @enumeration.type]) - [@enumeration]
|
||||
@enumerations = @enumeration.class.find(:all) - [@enumeration]
|
||||
#rescue
|
||||
# flash[:error] = 'Unable to delete enumeration'
|
||||
# redirect_to :action => 'index'
|
||||
|
||||
@@ -21,8 +21,8 @@ class IssueRelationsController < ApplicationController
|
||||
def new
|
||||
@relation = IssueRelation.new(params[:relation])
|
||||
@relation.issue_from = @issue
|
||||
if params[:relation] && !params[:relation][:issue_to_id].blank?
|
||||
@relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id])
|
||||
if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/)
|
||||
@relation.issue_to = Issue.visible.find_by_id(m[1].to_i)
|
||||
end
|
||||
@relation.save if request.post?
|
||||
respond_to do |format|
|
||||
|
||||
@@ -149,7 +149,7 @@ class IssuesController < ApplicationController
|
||||
if request.get? || request.xhr?
|
||||
@issue.start_date ||= Date.today
|
||||
else
|
||||
requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
|
||||
requested_status = IssueStatus.find_by_id(params[:issue][:status_id]) if params[:issue]
|
||||
# Check that the user is allowed to apply the requested status
|
||||
@issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
|
||||
call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue })
|
||||
@@ -223,10 +223,13 @@ class IssuesController < ApplicationController
|
||||
user = @issue.author
|
||||
text = @issue.description
|
||||
end
|
||||
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> "
|
||||
content << text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n"
|
||||
# Replaces pre blocks with [...]
|
||||
text = text.to_s.strip.gsub(%r{<pre>((.|\s)*?)</pre>}m, '[...]')
|
||||
content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> "
|
||||
content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n"
|
||||
|
||||
render(:update) { |page|
|
||||
page.<< "$('notes').value = \"#{content}\";"
|
||||
page.<< "$('notes').value = \"#{escape_javascript content}\";"
|
||||
page.show 'update'
|
||||
page << "Form.Element.focus('notes');"
|
||||
page << "Element.scrollTo('update');"
|
||||
@@ -280,14 +283,7 @@ class IssuesController < ApplicationController
|
||||
|
||||
def move
|
||||
@copy = params[:copy_options] && params[:copy_options][:copy]
|
||||
@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
|
||||
@allowed_projects = Issue.allowed_target_projects_on_move
|
||||
@target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id]
|
||||
@target_project ||= @project
|
||||
@trackers = @target_project.trackers
|
||||
|
||||
@@ -38,6 +38,7 @@ class MembersController < ApplicationController
|
||||
format.js {
|
||||
render(:update) {|page|
|
||||
page.replace_html "tab-content-members", :partial => 'projects/settings/members'
|
||||
page << 'hideOnLoad()'
|
||||
members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") }
|
||||
}
|
||||
}
|
||||
@@ -51,6 +52,7 @@ class MembersController < ApplicationController
|
||||
format.js {
|
||||
render(:update) {|page|
|
||||
page.replace_html "tab-content-members", :partial => 'projects/settings/members'
|
||||
page << 'hideOnLoad()'
|
||||
page.visual_effect(:highlight, "member-#{@member.id}")
|
||||
}
|
||||
}
|
||||
@@ -64,7 +66,11 @@ class MembersController < ApplicationController
|
||||
end
|
||||
respond_to do |format|
|
||||
format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project }
|
||||
format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members'} }
|
||||
format.js { render(:update) {|page|
|
||||
page.replace_html "tab-content-members", :partial => 'projects/settings/members'
|
||||
page << 'hideOnLoad()'
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ class ProjectsController < ApplicationController
|
||||
before_filter :authorize, :except => [ :index, :list, :add, :copy, :archive, :unarchive, :destroy, :activity ]
|
||||
before_filter :authorize_global, :only => :add
|
||||
before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ]
|
||||
accept_key_auth :activity
|
||||
accept_key_auth :activity, :index
|
||||
|
||||
after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|
|
||||
if controller.request.post?
|
||||
@@ -102,18 +102,20 @@ class ProjectsController < ApplicationController
|
||||
redirect_to :controller => 'admin', :action => 'projects'
|
||||
end
|
||||
else
|
||||
@project = Project.new(params[:project])
|
||||
@project.enabled_module_names = params[:enabled_modules]
|
||||
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')
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to :controller => 'admin', :action => 'projects'
|
||||
elsif !@project.new_record?
|
||||
# Project was created
|
||||
# But some objects were not copied due to validation failures
|
||||
# (eg. issues from disabled trackers)
|
||||
# TODO: inform about that
|
||||
redirect_to :controller => 'admin', :action => 'projects'
|
||||
Mailer.with_deliveries(params[:notifications] == '1') do
|
||||
@project = Project.new(params[:project])
|
||||
@project.enabled_module_names = params[:enabled_modules]
|
||||
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')
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
redirect_to :controller => 'admin', :action => 'projects'
|
||||
elsif !@project.new_record?
|
||||
# Project was created
|
||||
# But some objects were not copied due to validation failures
|
||||
# (eg. issues from disabled trackers)
|
||||
# TODO: inform about that
|
||||
redirect_to :controller => 'admin', :action => 'projects'
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
@@ -320,13 +322,9 @@ class ProjectsController < ApplicationController
|
||||
@issues_by_version = {}
|
||||
unless @selected_tracker_ids.empty?
|
||||
@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,
|
||||
:include => [:project, :status, :tracker, :priority],
|
||||
:conditions => conditions,
|
||||
:conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids},
|
||||
:order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id")
|
||||
@issues_by_version[version] = issues
|
||||
end
|
||||
|
||||
@@ -74,7 +74,7 @@ private
|
||||
|
||||
def find_optional_project
|
||||
@project = Project.find(params[:project_id]) if params[:project_id]
|
||||
User.current.allowed_to?(:save_queries, @project, :global => true)
|
||||
render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true)
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
@@ -61,7 +61,7 @@ class ReportsController < ApplicationController
|
||||
render :template => "reports/issue_report_details"
|
||||
when "subproject"
|
||||
@field = "project_id"
|
||||
@rows = @project.descendants.active
|
||||
@rows = @project.descendants.visible
|
||||
@data = issues_by_subproject
|
||||
@report_title = l(:field_subproject)
|
||||
render :template => "reports/issue_report_details"
|
||||
@@ -72,7 +72,7 @@ class ReportsController < ApplicationController
|
||||
@categories = @project.issue_categories
|
||||
@assignees = @project.members.collect { |m| m.user }.sort
|
||||
@authors = @project.members.collect { |m| m.user }.sort
|
||||
@subprojects = @project.descendants.active
|
||||
@subprojects = @project.descendants.visible
|
||||
issues_by_tracker
|
||||
issues_by_version
|
||||
issues_by_priority
|
||||
|
||||
@@ -46,11 +46,13 @@ class VersionsController < ApplicationController
|
||||
end
|
||||
|
||||
def destroy
|
||||
@version.destroy
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
rescue
|
||||
flash[:error] = l(:notice_unable_delete_version)
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
if @version.fixed_issues.empty?
|
||||
@version.destroy
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
else
|
||||
flash[:error] = l(:notice_unable_delete_version)
|
||||
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
|
||||
end
|
||||
end
|
||||
|
||||
def status_by
|
||||
|
||||
@@ -506,17 +506,17 @@ module ApplicationHelper
|
||||
# Forum messages:
|
||||
# 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|
|
||||
leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
|
||||
leading, esc, prefix, sep, identifier = $1, $2, $3, $5 || $7, $6 || $8
|
||||
link = nil
|
||||
if esc.nil?
|
||||
if prefix.nil? && sep == 'r'
|
||||
if project && (changeset = project.changesets.find_by_revision(oid))
|
||||
link = link_to("r#{oid}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => oid},
|
||||
if project && (changeset = project.changesets.find_by_revision(identifier))
|
||||
link = link_to("r#{identifier}", {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision},
|
||||
:class => 'changeset',
|
||||
:title => truncate_single_line(changeset.comments, :length => 100))
|
||||
end
|
||||
elsif sep == '#'
|
||||
oid = oid.to_i
|
||||
oid = identifier.to_i
|
||||
case prefix
|
||||
when nil
|
||||
if issue = Issue.visible.find_by_id(oid, :include => :status)
|
||||
@@ -547,7 +547,7 @@ module ApplicationHelper
|
||||
end
|
||||
elsif sep == ':'
|
||||
# removes the double quotes if any
|
||||
name = oid.gsub(%r{^"(.*)"$}, "\\1")
|
||||
name = identifier.gsub(%r{^"(.*)"$}, "\\1")
|
||||
case prefix
|
||||
when 'document'
|
||||
if project && document = project.documents.find_by_title(name)
|
||||
@@ -584,7 +584,7 @@ module ApplicationHelper
|
||||
end
|
||||
end
|
||||
end
|
||||
leading + (link || "#{prefix}#{sep}#{oid}")
|
||||
leading + (link || "#{prefix}#{sep}#{identifier}")
|
||||
end
|
||||
|
||||
text
|
||||
|
||||
@@ -52,17 +52,19 @@ module RepositoriesHelper
|
||||
else
|
||||
change
|
||||
end
|
||||
end.compact
|
||||
end.compact
|
||||
|
||||
tree = { }
|
||||
changes.each do |change|
|
||||
p = tree
|
||||
dirs = change.path.to_s.split('/').select {|d| !d.blank?}
|
||||
path = ''
|
||||
dirs.each do |dir|
|
||||
path += '/' + dir
|
||||
p[:s] ||= {}
|
||||
p = p[:s]
|
||||
p[dir] ||= {}
|
||||
p = p[dir]
|
||||
p[path] ||= {}
|
||||
p = p[path]
|
||||
end
|
||||
p[:c] = change
|
||||
end
|
||||
@@ -76,21 +78,26 @@ module RepositoriesHelper
|
||||
output = ''
|
||||
output << '<ul>'
|
||||
tree.keys.sort.each do |file|
|
||||
s = !tree[file][:s].nil?
|
||||
c = tree[file][:c]
|
||||
|
||||
style = 'change'
|
||||
style << ' folder' if s
|
||||
style << " change-#{c.action}" if c
|
||||
|
||||
text = h(file)
|
||||
unless c.nil?
|
||||
text = File.basename(h(file))
|
||||
if s = tree[file][:s]
|
||||
style << ' folder'
|
||||
path_param = to_path_param(@repository.relative_path(file))
|
||||
text = link_to(text, :controller => 'repositories',
|
||||
: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))
|
||||
text = link_to(text, :controller => 'repositories',
|
||||
:action => 'entry',
|
||||
:id => @project,
|
||||
:path => path_param,
|
||||
:rev => @changeset.revision) unless s || c.action == 'D'
|
||||
:rev => @changeset.revision) unless c.action == 'D'
|
||||
text << " - #{c.revision}" unless c.revision.blank?
|
||||
text << ' (' + link_to('diff', :controller => 'repositories',
|
||||
:action => 'diff',
|
||||
@@ -98,9 +105,8 @@ module RepositoriesHelper
|
||||
:path => path_param,
|
||||
:rev => @changeset.revision) + ') ' if c.action == 'M'
|
||||
text << ' ' + content_tag('span', c.from_path, :class => 'copied-from') unless c.from_path.blank?
|
||||
output << "<li class='#{style}'>#{text}</li>"
|
||||
end
|
||||
output << "<li class='#{style}'>#{text}</li>"
|
||||
output << render_changes_tree(tree[file][:s]) if s
|
||||
end
|
||||
output << '</ul>'
|
||||
output
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2008 Jean-Philippe Lang
|
||||
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -57,6 +57,10 @@ class Changeset < ActiveRecord::Base
|
||||
super
|
||||
end
|
||||
|
||||
def committer=(arg)
|
||||
write_attribute(:committer, self.class.to_utf8(arg.to_s))
|
||||
end
|
||||
|
||||
def project
|
||||
repository.project
|
||||
end
|
||||
@@ -80,9 +84,6 @@ class Changeset < ActiveRecord::Base
|
||||
ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip)
|
||||
# keywords used to fix issues
|
||||
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("|")
|
||||
return if kw_regexp.blank?
|
||||
@@ -100,7 +101,7 @@ class Changeset < ActiveRecord::Base
|
||||
action = match[0]
|
||||
target_issue_ids = match[1].scan(/\d+/)
|
||||
target_issues = find_referenced_issues_by_id(target_issue_ids)
|
||||
if fix_status && fix_keywords.include?(action.downcase)
|
||||
if fix_keywords.include?(action.downcase) && fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
|
||||
# update status of issues
|
||||
logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
|
||||
target_issues.each do |issue|
|
||||
@@ -114,7 +115,9 @@ class Changeset < ActiveRecord::Base
|
||||
end
|
||||
journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, csettext))
|
||||
issue.status = fix_status
|
||||
issue.done_ratio = done_ratio if done_ratio
|
||||
unless Setting.commit_fix_done_ratio.blank?
|
||||
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,
|
||||
{ :changeset => self, :issue => issue })
|
||||
issue.save
|
||||
@@ -123,7 +126,8 @@ class Changeset < ActiveRecord::Base
|
||||
referenced_issues += target_issues
|
||||
end
|
||||
|
||||
self.issues = referenced_issues.uniq
|
||||
referenced_issues.uniq!
|
||||
self.issues = referenced_issues unless referenced_issues.empty?
|
||||
end
|
||||
|
||||
def short_comments
|
||||
@@ -154,6 +158,7 @@ class Changeset < ActiveRecord::Base
|
||||
# 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
|
||||
def find_referenced_issues_by_id(ids)
|
||||
return [] if ids.compact.empty?
|
||||
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)
|
||||
}
|
||||
@@ -171,11 +176,17 @@ class Changeset < ActiveRecord::Base
|
||||
encoding = Setting.commit_logs_encoding.to_s.strip
|
||||
unless encoding.blank? || encoding == 'UTF-8'
|
||||
begin
|
||||
return Iconv.conv('UTF-8', encoding, str)
|
||||
str = Iconv.conv('UTF-8', encoding, str)
|
||||
rescue Iconv::Failure
|
||||
# do nothing here
|
||||
end
|
||||
end
|
||||
str
|
||||
# removes invalid UTF8 sequences
|
||||
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
|
||||
|
||||
@@ -80,7 +80,7 @@ class Issue < ActiveRecord::Base
|
||||
end
|
||||
|
||||
def copy_from(arg)
|
||||
issue = arg.is_a?(Issue) ? arg : Issue.find(arg)
|
||||
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
|
||||
self.attributes = issue.attributes.dup.except("id", "created_on", "updated_on")
|
||||
self.custom_values = issue.custom_values.collect {|v| v.clone}
|
||||
self.status = issue.status
|
||||
@@ -92,7 +92,7 @@ class Issue < ActiveRecord::Base
|
||||
def move_to(new_project, new_tracker = nil, options = {})
|
||||
options ||= {}
|
||||
issue = options[:copy] ? self.clone : self
|
||||
transaction do
|
||||
ret = Issue.transaction do
|
||||
if new_project && issue.project_id != new_project.id
|
||||
# delete issue relations
|
||||
unless Setting.cross_project_issue_relations?
|
||||
@@ -129,12 +129,12 @@ class Issue < ActiveRecord::Base
|
||||
# Manually update project_id on related time entries
|
||||
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
|
||||
end
|
||||
true
|
||||
else
|
||||
Issue.connection.rollback_db_transaction
|
||||
return false
|
||||
raise ActiveRecord::Rollback
|
||||
end
|
||||
end
|
||||
return issue
|
||||
ret ? issue : false
|
||||
end
|
||||
|
||||
def priority_id=(pid)
|
||||
@@ -159,7 +159,8 @@ class Issue < ActiveRecord::Base
|
||||
end
|
||||
send :attributes_without_tracker_first=, new_attributes, *args
|
||||
end
|
||||
alias_method_chain :attributes=, :tracker_first
|
||||
# Do not redefine alias chain on reload (see #4838)
|
||||
alias_method_chain(:attributes=, :tracker_first) unless method_defined?(:attributes_without_tracker_first=)
|
||||
|
||||
def estimated_hours=(h)
|
||||
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
|
||||
@@ -388,6 +389,22 @@ 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])
|
||||
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
|
||||
|
||||
# Update issues so their versions are not pointing to a
|
||||
|
||||
@@ -49,7 +49,7 @@ class MailHandler < ActionMailer::Base
|
||||
logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]" if logger && logger.info
|
||||
return false
|
||||
end
|
||||
@user = User.find_by_mail(sender_email)
|
||||
@user = User.find_by_mail(sender_email) if sender_email.present?
|
||||
if @user && !@user.active?
|
||||
logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]" if logger && logger.info
|
||||
return false
|
||||
|
||||
@@ -114,11 +114,11 @@ class Mailer < ActionMailer::Base
|
||||
when 'Project'
|
||||
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
|
||||
added_to = "#{l(:label_project)}: #{container}"
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
|
||||
when 'Version'
|
||||
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
|
||||
added_to = "#{l(:label_version)}: #{container.name}"
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}
|
||||
recipients container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail}
|
||||
when 'Document'
|
||||
added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id)
|
||||
added_to = "#{l(:label_document)}: #{container.title}"
|
||||
@@ -310,6 +310,15 @@ class Mailer < ActionMailer::Base
|
||||
deliver_reminder(assignee, issues, days) unless assignee.nil?
|
||||
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
|
||||
def initialize_defaults(method_name)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class Principal < ActiveRecord::Base
|
||||
set_table_name 'users'
|
||||
set_table_name "#{table_name_prefix}users#{table_name_suffix}"
|
||||
|
||||
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"
|
||||
|
||||
@@ -56,7 +56,7 @@ class Project < ActiveRecord::Base
|
||||
:delete_permission => :manage_files
|
||||
|
||||
acts_as_customizable
|
||||
acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil
|
||||
acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil
|
||||
acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
|
||||
:url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}},
|
||||
:author => nil
|
||||
@@ -249,7 +249,7 @@ class Project < ActiveRecord::Base
|
||||
return @allowed_parents if @allowed_parents
|
||||
@allowed_parents = Project.find(:all, :conditions => Project.allowed_to_condition(User.current, :add_subprojects))
|
||||
@allowed_parents = @allowed_parents - self_and_descendants
|
||||
if User.current.allowed_to?(:add_project, nil, :global => true)
|
||||
if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?)
|
||||
@allowed_parents << nil
|
||||
end
|
||||
unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent)
|
||||
@@ -512,11 +512,23 @@ class Project < ActiveRecord::Base
|
||||
unless project.wiki.nil?
|
||||
self.wiki ||= Wiki.new
|
||||
wiki.attributes = project.wiki.attributes.dup.except("id", "project_id")
|
||||
wiki_pages_map = {}
|
||||
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_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id"))
|
||||
new_wiki_page.content = new_wiki_content
|
||||
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
|
||||
|
||||
@@ -210,6 +210,10 @@ class Query < ActiveRecord::Base
|
||||
add_custom_fields_filters(@project.all_issue_custom_fields)
|
||||
else
|
||||
# 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}))
|
||||
end
|
||||
@available_filters
|
||||
|
||||
@@ -136,6 +136,7 @@ class Repository < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
@committers = nil
|
||||
@found_committer_users = nil
|
||||
true
|
||||
else
|
||||
false
|
||||
@@ -146,24 +147,34 @@ class Repository < ActiveRecord::Base
|
||||
# It will return nil if the committer is not yet mapped and if no User
|
||||
# with the same username or email was found
|
||||
def find_committer_user(committer)
|
||||
if committer
|
||||
unless committer.blank?
|
||||
@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)
|
||||
if c && c.user
|
||||
c.user
|
||||
user = c.user
|
||||
elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/
|
||||
username, email = $1.strip, $3
|
||||
u = User.find_by_login(username)
|
||||
u ||= User.find_by_mail(email) unless email.blank?
|
||||
u
|
||||
user = u
|
||||
end
|
||||
@found_committer_users[committer] = user
|
||||
user
|
||||
end
|
||||
end
|
||||
|
||||
# fetch new changesets for all repositories
|
||||
# can be called periodically by an external script
|
||||
# Fetches new changesets for all repositories of active projects
|
||||
# Can be called periodically by an external script
|
||||
# eg. ruby script/runner "Repository.fetch_changesets"
|
||||
def self.fetch_changesets
|
||||
find(:all).each(&:fetch_changesets)
|
||||
Project.active.has_module(:repository).find(:all, :include => :repository).each do |project|
|
||||
if project.repository
|
||||
project.repository.fetch_changesets
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# scan changeset comments to find related and fixed issues for all repositories
|
||||
|
||||
@@ -40,23 +40,26 @@ class Repository::Git < Repository
|
||||
# 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
|
||||
# it knows about. However, with git, you never know if people have merged
|
||||
# commits into the middle of the repository history, so we always have to
|
||||
# parse the entire log.
|
||||
# commits into the middle of the repository history, so we should parse
|
||||
# the entire log. Since it's way too slow for large repositories, we only
|
||||
# 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
|
||||
# Save ourselves an expensive operation if we're already up to date
|
||||
return if scm.num_revisions == changesets.count
|
||||
c = changesets.find(:first, :order => 'committed_on DESC')
|
||||
since = (c ? c.committed_on - 7.days : nil)
|
||||
|
||||
revisions = scm.revisions('', nil, nil, :all => true)
|
||||
revisions = scm.revisions('', nil, nil, :all => true, :since => since)
|
||||
return if revisions.nil? || revisions.empty?
|
||||
|
||||
# Find revisions that redmine knows about already
|
||||
existing_revisions = changesets.find(:all).map!{|c| c.scmid}
|
||||
recent_changesets = changesets.find(:all, :conditions => ['committed_on >= ?', since])
|
||||
|
||||
# Clean out revisions that are no longer in git
|
||||
Changeset.delete_all(["scmid NOT IN (?) AND repository_id = (?)", revisions.map{|r| r.scmid}, self.id])
|
||||
recent_changesets.each {|c| c.destroy unless revisions.detect {|r| r.scmid.to_s == c.scmid.to_s }}
|
||||
|
||||
# Subtract revisions that redmine already knows about
|
||||
revisions.reject!{|r| existing_revisions.include?(r.scmid)}
|
||||
recent_revisions = recent_changesets.map{|c| c.scmid}
|
||||
revisions.reject!{|r| recent_revisions.include?(r.scmid)}
|
||||
|
||||
# Save the remaining ones to the database
|
||||
revisions.each{|r| r.save(self)} unless revisions.nil?
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# redMine - project management software
|
||||
# Copyright (C) 2006 Jean-Philippe Lang
|
||||
# Redmine - project management software
|
||||
# Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
@@ -16,10 +16,9 @@
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
class Version < ActiveRecord::Base
|
||||
before_destroy :check_integrity
|
||||
after_update :update_issues_from_sharing_change
|
||||
belongs_to :project
|
||||
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
|
||||
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify
|
||||
acts_as_customizable
|
||||
acts_as_attachable :view_permission => :view_files,
|
||||
:delete_permission => :manage_files
|
||||
@@ -155,10 +154,7 @@ class Version < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def check_integrity
|
||||
raise "Can't delete version" if self.fixed_issues.find(:first)
|
||||
end
|
||||
private
|
||||
|
||||
# Update the issue's fixed versions. Used if a version's sharing changes.
|
||||
def update_issues_from_sharing_change
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<%= call_hook :view_account_login_top %>
|
||||
<div id="login-form">
|
||||
<% form_tag({:action=> "login"}) do %>
|
||||
<%= back_url_hidden_field_tag %>
|
||||
@@ -38,3 +39,4 @@
|
||||
<%= javascript_tag "Form.Element.focus('username');" %>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= call_hook :view_account_login_bottom %>
|
||||
|
||||
@@ -26,3 +26,7 @@
|
||||
<% end %>
|
||||
|
||||
<% html_title @document.title -%>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= stylesheet_link_tag 'scm' %>
|
||||
<% end %>
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %>
|
||||
<fieldset><legend><%=l(:label_user_new)%></legend>
|
||||
|
||||
<p><%= text_field_tag 'user_search', nil, :size => "40" %></p>
|
||||
<p><%= text_field_tag 'user_search', nil %></p>
|
||||
<%= observe_field(:user_search,
|
||||
:frequency => 0.5,
|
||||
:update => :users,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<% end %>
|
||||
<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><%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %></td>
|
||||
<td class="id"><%= 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 %>
|
||||
</tr>
|
||||
<% end -%>
|
||||
|
||||
@@ -86,7 +86,6 @@ top = headers_height + 8
|
||||
<%= link_to_issue i %>
|
||||
<% else %>
|
||||
<span class="icon icon-package">
|
||||
<%= h("#{i.project} -") unless @project && @project == i.project %>
|
||||
<%= link_to_version i %>
|
||||
</span>
|
||||
<% end %>
|
||||
@@ -211,8 +210,7 @@ top = headers_height + 10
|
||||
%>
|
||||
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone"> </div>
|
||||
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
|
||||
<%= h("#{i.project} -") unless @project && @project == i.project %>
|
||||
<strong><%=h i %></strong>
|
||||
<strong><%= format_version_name i %></strong>
|
||||
</div>
|
||||
<% end %>
|
||||
<% top = top + 20
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
|
||||
<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
|
||||
<%= hidden_field_tag('project_id', @project.to_param) if @project %>
|
||||
<div id="query_form_content">
|
||||
<fieldset id="filters" class="collapsible">
|
||||
<div id="query_form_content" class="hide-when-print">
|
||||
<fieldset id="filters" class="collapsible <%= @query.new_record? ? "" : "collapsed" %>">
|
||||
<legend onclick="toggleFieldset(this);"><%= l(:label_filter_plural) %></legend>
|
||||
<div>
|
||||
<div style="<%= @query.new_record? ? "" : "display: none;" %>">
|
||||
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
|
||||
</div>
|
||||
</fieldset>
|
||||
@@ -33,7 +33,7 @@
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
<p class="buttons">
|
||||
<p class="buttons hide-when-print">
|
||||
|
||||
<%= link_to_remote l(:button_apply),
|
||||
{ :url => { :set_filter => 1 },
|
||||
|
||||
@@ -40,9 +40,11 @@
|
||||
|
||||
<h1><%= page_header_title %></h1>
|
||||
|
||||
<% if display_main_menu?(@project) %>
|
||||
<div id="main-menu">
|
||||
<%= render_main_menu(@project) %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<h1><%= link_to "#{issue.tracker.name} ##{issue.id}: #{issue.subject}", issue_url %></h1>
|
||||
<h1><%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %></h1>
|
||||
|
||||
<ul>
|
||||
<li><%=l(:field_author)%>: <%= issue.author %></li>
|
||||
<li><%=l(:field_status)%>: <%= issue.status %></li>
|
||||
<li><%=l(:field_priority)%>: <%= issue.priority %></li>
|
||||
<li><%=l(:field_assigned_to)%>: <%= issue.assigned_to %></li>
|
||||
<li><%=l(:field_category)%>: <%= issue.category %></li>
|
||||
<li><%=l(:field_fixed_version)%>: <%= issue.fixed_version %></li>
|
||||
<li><%=l(:field_author)%>: <%=h issue.author %></li>
|
||||
<li><%=l(:field_status)%>: <%=h issue.status %></li>
|
||||
<li><%=l(:field_priority)%>: <%=h issue.priority %></li>
|
||||
<li><%=l(:field_assigned_to)%>: <%=h issue.assigned_to %></li>
|
||||
<li><%=l(:field_category)%>: <%=h issue.category %></li>
|
||||
<li><%=l(:field_fixed_version)%>: <%=h issue.fixed_version %></li>
|
||||
<% issue.custom_values.each do |c| %>
|
||||
<li><%= c.custom_field.name %>: <%= show_value(c) %></li>
|
||||
<li><%=h c.custom_field.name %>: <%=h show_value(c) %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
<p><%= l(:mail_body_account_activation_request, @user.login) %></p>
|
||||
<p><%= l(:mail_body_account_activation_request, h(@user.login)) %></p>
|
||||
<p><%= link_to @url, @url %></p>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<% if @user.auth_source %>
|
||||
<p><%= l(:mail_body_account_information_external, @user.auth_source.name) %></p>
|
||||
<p><%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %></p>
|
||||
<% else %>
|
||||
<p><%= l(:mail_body_account_information) %>:</p>
|
||||
<ul>
|
||||
<li><%= l(:field_login) %>: <%= @user.login %></li>
|
||||
<li><%= l(:field_password) %>: <%= @password %></li>
|
||||
<li><%= l(:field_login) %>: <%=h @user.login %></li>
|
||||
<li><%= l(:field_password) %>: <%=h @password %></li>
|
||||
</ul>
|
||||
<% end %>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<%= link_to @added_to, @added_to_url %><br />
|
||||
|
||||
<ul><% @attachments.each do |attachment | %>
|
||||
<li><%= attachment.filename %></li>
|
||||
<li><%=h attachment.filename %></li>
|
||||
<% end %></ul>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= link_to @document.title, @document_url %> (<%= @document.category.name %>)<br />
|
||||
<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)<br />
|
||||
<br />
|
||||
<%= textilizable(@document, :description, :only_path => false) %>
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %>
|
||||
<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %>
|
||||
<hr />
|
||||
<%= render :partial => "issue_text_html", :locals => { :issue => @issue, :issue_url => @issue_url } %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %>
|
||||
<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %>
|
||||
|
||||
<ul>
|
||||
<% for detail in @journal.details %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<p><%= l(:mail_body_lost_password) %><br />
|
||||
<%= auto_link(@url) %></p>
|
||||
|
||||
<p><%= l(:field_login) %>: <b><%= @token.user.login %></b></p>
|
||||
<p><%= l(:field_login) %>: <b><%=h @token.user.login %></b></p>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to @message.subject, @message_url %></h1>
|
||||
<em><%= @message.author %></em>
|
||||
<h1><%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %></h1>
|
||||
<em><%=h @message.author %></em>
|
||||
|
||||
<%= textilizable(@message, :content, :only_path => false) %>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h1><%= link_to @news.title, @news_url %></h1>
|
||||
<em><%= @news.author.name %></em>
|
||||
<h1><%= link_to(h(@news.title), @news_url) %></h1>
|
||||
<em><%=h @news.author.name %></em>
|
||||
|
||||
<%= textilizable(@news, :description, :only_path => false) %>
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
<% if Setting.rest_api_enabled? %>
|
||||
<h4><%= l(:label_api_access_key) %></h4>
|
||||
<p>
|
||||
<div>
|
||||
<%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%>
|
||||
<pre id='api-access-key' class='autoscroll'><%= @user.api_key %></pre>
|
||||
</p>
|
||||
</div>
|
||||
<%= javascript_tag("$('api-access-key').hide();") %>
|
||||
<p>
|
||||
<% if @user.api_token %>
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
<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>
|
||||
<%= hidden_field_tag 'only[]', '' %>
|
||||
<br />
|
||||
<label class="block"><%= check_box_tag 'notifications', 1, params[:notifications] %> <%= l(:label_project_copy_notifications) %></label>
|
||||
</fieldset>
|
||||
|
||||
<%= submit_tag l(:button_copy) %>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<% content_for :header_tags do %>
|
||||
<%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %>
|
||||
<% end %>
|
||||
|
||||
<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_issue_view_all), { :controller => 'issues' }) + ' |' if User.current.allowed_to?(:view_issues, nil, :global => true) %>
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
<% remote_form_for(:member, @member, :url => {:controller => 'members', :action => 'new', :id => @project}, :method => :post) do |f| %>
|
||||
<fieldset><legend><%=l(:label_member_new)%></legend>
|
||||
|
||||
<p><%= text_field_tag 'principal_search', nil, :size => "40" %></p>
|
||||
<p><%= text_field_tag 'principal_search', nil %></p>
|
||||
<%= observe_field(:principal_search,
|
||||
:frequency => 0.5,
|
||||
:update => :principals,
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
<h2><%=l(:label_overview)%></h2>
|
||||
|
||||
<div class="splitcontentleft">
|
||||
<%= textilizable @project.description %>
|
||||
<div class="wiki">
|
||||
<%= textilizable @project.description %>
|
||||
</div>
|
||||
<ul>
|
||||
<% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= link_to(h(@project.homepage), @project.homepage) %></li><% end %>
|
||||
<% unless @project.homepage.blank? %><li><%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %></li><% end %>
|
||||
<% if @subprojects.any? %>
|
||||
<li><%=l(:label_subproject_plural)%>:
|
||||
<%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %></li>
|
||||
|
||||
@@ -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 %>
|
||||
<% end %>
|
||||
|
||||
<%= "@ #{revision}" if revision %>
|
||||
<%= "@ #{h revision}" if revision %>
|
||||
|
||||
<% html_title(with_leading_slash(path)) -%>
|
||||
|
||||
@@ -1,4 +1,70 @@
|
||||
# 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:
|
||||
delivery_method: :smtp
|
||||
|
||||
@@ -25,5 +25,5 @@ config.action_controller.session = {
|
||||
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 "edavis10-object_daddy", :lib => "object_daddy"
|
||||
config.gem "mocha"
|
||||
|
||||
@@ -1,29 +1 @@
|
||||
# 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"
|
||||
instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
|
||||
|
||||
@@ -1,29 +1 @@
|
||||
# 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"
|
||||
instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb'))
|
||||
|
||||
@@ -881,4 +881,4 @@ bg:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -905,3 +905,4 @@ bs:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -884,3 +884,4 @@ ca:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -887,3 +887,4 @@ cs:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -907,3 +907,4 @@ da:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -907,3 +907,4 @@ de:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -887,3 +887,4 @@ el:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -748,6 +748,7 @@ en:
|
||||
label_api_access_key: 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_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
button_login: Login
|
||||
button_submit: Submit
|
||||
|
||||
@@ -931,3 +931,4 @@ es:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -917,3 +917,4 @@ fi:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -764,6 +764,7 @@ fr:
|
||||
label_missing_feeds_access_key: Clé d'accès RSS manquante
|
||||
label_close_versions: Fermer les versions terminées
|
||||
label_revision_id: Revision {{value}}
|
||||
label_project_copy_notifications: Envoyer les notifications durant la copie du projet
|
||||
|
||||
button_login: Connexion
|
||||
button_submit: Soumettre
|
||||
@@ -811,10 +812,10 @@ fr:
|
||||
|
||||
status_active: actif
|
||||
status_registered: enregistré
|
||||
status_locked: vérouillé
|
||||
status_locked: verrouillé
|
||||
|
||||
version_status_open: ouvert
|
||||
version_status_locked: vérouillé
|
||||
version_status_locked: verrouillé
|
||||
version_status_closed: fermé
|
||||
|
||||
text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée
|
||||
|
||||
@@ -907,3 +907,4 @@ gl:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -891,3 +891,4 @@ he:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -894,3 +894,4 @@ hr:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -912,3 +912,4 @@
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -899,3 +899,4 @@ id:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -894,4 +894,4 @@ it:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -916,3 +916,4 @@ ja:
|
||||
enumeration_activities: 作業分類 (時間トラッキング)
|
||||
enumeration_system_activity: システム作業分類
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -947,3 +947,4 @@ ko:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -955,3 +955,4 @@ lt:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -869,3 +869,4 @@ nl:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -882,3 +882,4 @@
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -912,3 +912,4 @@ pl:
|
||||
permission_export_wiki_pages: Eksport stron wiki
|
||||
permission_manage_project_activities: Zarządzanie aktywnościami projektu
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -915,3 +915,4 @@ pt-BR:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -899,3 +899,4 @@ pt:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -884,3 +884,4 @@ ro:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -995,3 +995,4 @@ ru:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -886,3 +886,4 @@ sk:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -883,3 +883,4 @@ sl:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -902,3 +902,4 @@
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -936,3 +936,4 @@ sv:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -884,3 +884,4 @@ th:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -914,3 +914,4 @@ tr:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -883,3 +883,4 @@ uk:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -946,3 +946,4 @@ vi:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -978,3 +978,4 @@
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -909,4 +909,4 @@ zh:
|
||||
permission_export_wiki_pages: Export wiki pages
|
||||
setting_cache_formatted_text: Cache formatted text
|
||||
permission_manage_project_activities: Manage project activities
|
||||
|
||||
label_project_copy_notifications: Send email notifications during the project copy
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
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
|
||||
@@ -4,6 +4,77 @@ Redmine - project management software
|
||||
Copyright (C) 2006-2010 Jean-Philippe Lang
|
||||
http://www.redmine.org/
|
||||
|
||||
== v1.0.0
|
||||
|
||||
Adds context menu to the roadmap issue lists
|
||||
|
||||
== 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
|
||||
|
||||
* Fixed: Sub-project repository commits not displayed on parent project issues
|
||||
|
||||
18
doc/INSTALL
18
doc/INSTALL
@@ -7,7 +7,11 @@ http://www.redmine.org/
|
||||
|
||||
== Requirements
|
||||
|
||||
* Ruby on Rails 2.3.5
|
||||
* Ruby 1.8.6 or 1.8.7
|
||||
|
||||
* Ruby on Rails 2.3.5 (official downloadable Redmine releases are packaged with
|
||||
the appropriate Rails version)
|
||||
|
||||
* A database:
|
||||
* MySQL (tested with MySQL 5)
|
||||
* PostgreSQL (tested with PostgreSQL 8.1)
|
||||
@@ -26,15 +30,15 @@ Optional:
|
||||
3. Configure database parameters in config/database.yml
|
||||
for "production" environment (default database is MySQL)
|
||||
|
||||
4. Create the database structure. Under the application main directory:
|
||||
4. Generate a session store secret
|
||||
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"
|
||||
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
|
||||
The user who runs Redmine must have write permission on the following
|
||||
subdirectories: files, log, tmp (create the last one if not present).
|
||||
|
||||
@@ -12,18 +12,18 @@ http://www.redmine.org/
|
||||
2. Copy your database settings (RAILS_ROOT/config/database.yml)
|
||||
and SMTP settings (RAILS_ROOT/config/email.yml)
|
||||
into the new config directory
|
||||
DO NOT REPLACE ANY OTHERS FILES.
|
||||
|
||||
3. Migrate your database (please make a backup before doing this):
|
||||
rake db:migrate RAILS_ENV="production"
|
||||
DO NOT REPLACE OR EDIT ANY OTHER FILES.
|
||||
|
||||
4. Copy the RAILS_ROOT/files directory content into your new installation
|
||||
This directory contains all the attached files
|
||||
|
||||
5. Generate a session store secret
|
||||
3. 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
|
||||
rake generate_session_store
|
||||
|
||||
4. Migrate your database (please make a backup before doing this):
|
||||
rake db:migrate RAILS_ENV="production"
|
||||
|
||||
5. Copy the RAILS_ROOT/files directory content into your new installation
|
||||
This directory contains all the attached files
|
||||
|
||||
== Notes
|
||||
|
||||
|
||||
@@ -221,10 +221,14 @@ def other_read_right?(file)
|
||||
end
|
||||
|
||||
def owner_name(file)
|
||||
RUBY_PLATFORM =~ /mswin/ ?
|
||||
mswin? ?
|
||||
$svn_owner :
|
||||
Etc.getpwuid( File.stat(file).uid ).name
|
||||
end
|
||||
|
||||
def mswin?
|
||||
(RUBY_PLATFORM =~ /(:?mswin|mingw)/) || (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i)
|
||||
end
|
||||
|
||||
projects.each do |project|
|
||||
log("treating project #{project.name}", :level => 1)
|
||||
@@ -303,4 +307,4 @@ projects.each do |project|
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ class RedminePluginControllerGenerator < ControllerGenerator
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
runtime_args = runtime_args.dup
|
||||
usage if runtime_args.empty?
|
||||
@plugin_name = "redmine_" + runtime_args.shift.underscore
|
||||
@plugin_pretty_name = plugin_name.titleize
|
||||
@plugin_path = "vendor/plugins/#{plugin_name}"
|
||||
|
||||
@@ -6,6 +6,7 @@ class RedminePluginModelGenerator < ModelGenerator
|
||||
|
||||
def initialize(runtime_args, runtime_options = {})
|
||||
runtime_args = runtime_args.dup
|
||||
usage if runtime_args.empty?
|
||||
@plugin_name = "redmine_" + runtime_args.shift.underscore
|
||||
@plugin_pretty_name = plugin_name.titleize
|
||||
@plugin_path = "vendor/plugins/#{plugin_name}"
|
||||
|
||||
@@ -818,7 +818,7 @@ class RedCloth3 < String
|
||||
post = ")"+post # add closing parenth to post
|
||||
end
|
||||
atts = pba( atts )
|
||||
atts = " href=\"#{ url }#{ slash }\"#{ atts }"
|
||||
atts = " href=\"#{ htmlesc url }#{ slash }\"#{ atts }"
|
||||
atts << " title=\"#{ htmlesc title }\"" if title
|
||||
atts = shelve( atts ) if atts
|
||||
|
||||
|
||||
@@ -84,6 +84,14 @@ module TreeNodePatch
|
||||
|
||||
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
|
||||
# it's parent
|
||||
def position
|
||||
@@ -158,6 +166,11 @@ module Redmine
|
||||
render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project)
|
||||
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)
|
||||
links = []
|
||||
menu_items_for(menu, project) do |node|
|
||||
@@ -352,7 +365,7 @@ module Redmine
|
||||
target_root.add(MenuItem.new(name, url, options))
|
||||
end
|
||||
|
||||
elsif options.delete(:last)
|
||||
elsif options[:last] # don't delete, needs to be stored
|
||||
target_root.add_last(MenuItem.new(name, url, options))
|
||||
else
|
||||
target_root.add(MenuItem.new(name, url, options))
|
||||
@@ -386,7 +399,7 @@ module Redmine
|
||||
|
||||
class MenuItem < Tree::TreeNode
|
||||
include Redmine::I18n
|
||||
attr_reader :name, :url, :param, :condition, :parent, :child_menus
|
||||
attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last
|
||||
|
||||
def initialize(name, url, options)
|
||||
raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call)
|
||||
@@ -403,6 +416,7 @@ module Redmine
|
||||
@html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ')
|
||||
@parent = options[:parent]
|
||||
@child_menus = options[:children]
|
||||
@last = options[:last] || false
|
||||
super @name.to_sym
|
||||
end
|
||||
|
||||
|
||||
@@ -286,21 +286,23 @@ module Redmine
|
||||
end
|
||||
|
||||
def save(repo)
|
||||
if repo.changesets.find_by_scmid(scmid.to_s).nil?
|
||||
changeset = Changeset.create!(
|
||||
Changeset.transaction do
|
||||
changeset = Changeset.new(
|
||||
:repository => repo,
|
||||
:revision => identifier,
|
||||
:scmid => scmid,
|
||||
:committer => author,
|
||||
:committed_on => time,
|
||||
:comments => message)
|
||||
|
||||
paths.each do |file|
|
||||
Change.create!(
|
||||
:changeset => changeset,
|
||||
:action => file[:action],
|
||||
:path => file[:path])
|
||||
end
|
||||
|
||||
if changeset.save
|
||||
paths.each do |file|
|
||||
Change.create(
|
||||
:changeset => changeset,
|
||||
:action => file[:action],
|
||||
:path => file[:path])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -56,14 +56,14 @@ module Redmine
|
||||
shellout(cmd) do |io|
|
||||
prefix = "#{url}/#{path}".gsub('\\', '/')
|
||||
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|
|
||||
next unless line =~ re
|
||||
entries << Entry.new({:name => $2.strip,
|
||||
:path => ((path.empty? ? "" : "#{path}/") + $2.strip),
|
||||
:kind => ($3.blank? ? 'file' : 'dir'),
|
||||
entries << Entry.new({:name => $3.strip,
|
||||
:path => ((path.empty? ? "" : "#{path}/") + $3.strip),
|
||||
:kind => ($4.blank? ? 'file' : 'dir'),
|
||||
:size => nil,
|
||||
:lastrev => Revision.new(:revision => $4.strip)
|
||||
:lastrev => Revision.new(:revision => $5.strip)
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,21 +33,22 @@ module Redmine
|
||||
end
|
||||
|
||||
def branches
|
||||
branches = []
|
||||
return @branches if @branches
|
||||
@branches = []
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} branch"
|
||||
shellout(cmd) do |io|
|
||||
io.each_line do |line|
|
||||
branches << line.match('\s*\*?\s*(.*)$')[1]
|
||||
@branches << line.match('\s*\*?\s*(.*)$')[1]
|
||||
end
|
||||
end
|
||||
branches.sort!
|
||||
@branches.sort!
|
||||
end
|
||||
|
||||
def tags
|
||||
tags = []
|
||||
return @tags if @tags
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} tag"
|
||||
shellout(cmd) do |io|
|
||||
io.readlines.sort!.map{|t| t.strip}
|
||||
@tags = io.readlines.sort!.map{|t| t.strip}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,20 +111,16 @@ module Redmine
|
||||
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={})
|
||||
revisions = Revisions.new
|
||||
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} log --find-copies-harder --raw --date=iso --pretty=fuller"
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller"
|
||||
cmd << " --reverse" if options[:reverse]
|
||||
cmd << " --all" if options[:all]
|
||||
cmd << " -n #{options[:limit]} " if options[:limit]
|
||||
cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from
|
||||
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?
|
||||
|
||||
shellout(cmd) do |io|
|
||||
@@ -230,16 +227,26 @@ module Redmine
|
||||
|
||||
def annotate(path, identifier=nil)
|
||||
identifier = 'HEAD' if identifier.blank?
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} blame -l #{shell_quote identifier} -- #{shell_quote path}"
|
||||
cmd = "#{GIT_BIN} --git-dir #{target('')} blame -p #{shell_quote identifier} -- #{shell_quote path}"
|
||||
blame = Annotate.new
|
||||
content = nil
|
||||
shellout(cmd) { |io| io.binmode; content = io.read }
|
||||
return nil if $? && $?.exitstatus != 0
|
||||
# git annotates binary files
|
||||
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|
|
||||
next unless line =~ /([0-9a-f]{39,40})\s\((\w*)[^\)]*\)(.*)/
|
||||
blame.add_line($3.rstrip, Revision.new(:identifier => $1, :author => $2.strip))
|
||||
if line =~ /^([0-9a-f]{39,40})\s.*/
|
||||
identifier = $1
|
||||
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
|
||||
blame
|
||||
end
|
||||
|
||||
@@ -4,7 +4,7 @@ module Redmine
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 0
|
||||
MINOR = 9
|
||||
TINY = 2
|
||||
TINY = 5
|
||||
|
||||
# Branch values:
|
||||
# * official release: nil
|
||||
|
||||
@@ -25,17 +25,17 @@ module Redmine
|
||||
end
|
||||
|
||||
def register(name, formatter, helper)
|
||||
raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_sym]
|
||||
@@formatters[name.to_sym] = {:formatter => formatter, :helper => helper}
|
||||
raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s]
|
||||
@@formatters[name.to_s] = {:formatter => formatter, :helper => helper}
|
||||
end
|
||||
|
||||
def formatter_for(name)
|
||||
entry = @@formatters[name.to_sym]
|
||||
entry = @@formatters[name.to_s]
|
||||
(entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter
|
||||
end
|
||||
|
||||
def helper_for(name)
|
||||
entry = @@formatters[name.to_sym]
|
||||
entry = @@formatters[name.to_s]
|
||||
(entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper
|
||||
end
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user