##// END OF EJS Templates
Search engines now supports pagination....
Jean-Philippe Lang -
r755:a96421019f3a
parent child
Show More
@@ -0,0 +1,2
1 require File.dirname(__FILE__) + '/lib/acts_as_searchable'
2 ActiveRecord::Base.send(:include, Redmine::Acts::Searchable)
@@ -0,0 +1,89
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
18 module Redmine
19 module Acts
20 module Searchable
21 def self.included(base)
22 base.extend ClassMethods
23 end
24
25 module ClassMethods
26 def acts_as_searchable(options = {})
27 return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods)
28
29 cattr_accessor :searchable_options
30 self.searchable_options = options
31
32 if searchable_options[:columns].nil?
33 raise 'No searchable column defined.'
34 elsif !searchable_options[:columns].is_a?(Array)
35 searchable_options[:columns] = [] << searchable_options[:columns]
36 end
37
38 if searchable_options[:project_key]
39 elsif column_names.include?('project_id')
40 searchable_options[:project_key] = "#{table_name}.project_id"
41 else
42 raise 'No project key defined.'
43 end
44
45 if searchable_options[:date_column]
46 elsif column_names.include?('created_on')
47 searchable_options[:date_column] = "#{table_name}.created_on"
48 else
49 raise 'No date column defined defined.'
50 end
51
52 send :include, Redmine::Acts::Searchable::InstanceMethods
53 end
54 end
55
56 module InstanceMethods
57 def self.included(base)
58 base.extend ClassMethods
59 end
60
61 module ClassMethods
62 def search(tokens, all_tokens, project, options={})
63 tokens = [] << tokens unless tokens.is_a?(Array)
64 find_options = {:include => searchable_options[:include]}
65 find_options[:limit] = options[:limit] if options[:limit]
66 find_options[:order] = "#{searchable_options[:date_column]} " + (options[:before] ? 'DESC' : 'ASC')
67
68 sql = ([ '(' + searchable_options[:columns].collect {|column| "(LOWER(#{column}) LIKE ?)"}.join(' OR ') + ')' ] * tokens.size).join(all_tokens ? ' AND ' : ' OR ')
69 if options[:offset]
70 sql = "(#{sql}) AND (#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
71 end
72 find_options[:conditions] = [sql, * (tokens * searchable_options[:columns].size).sort]
73
74 results = with_scope(:find => {:conditions => ["#{searchable_options[:project_key]} = ?", project.id]}) do
75 find(:all, find_options)
76 end
77 if searchable_options[:with]
78 searchable_options[:with].each do |model, assoc|
79 results += model.to_s.camelcase.constantize.search(tokens, all_tokens, project, options).collect {|r| r.send assoc}
80 end
81 results.uniq!
82 end
83 results
84 end
85 end
86 end
87 end
88 end
89 end
@@ -1,97 +1,104
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class SearchController < ApplicationController
18 class SearchController < ApplicationController
19 layout 'base'
19 layout 'base'
20
20
21 helper :messages
21 helper :messages
22 include MessagesHelper
22 include MessagesHelper
23
23
24 def index
24 def index
25 @question = params[:q] || ""
25 @question = params[:q] || ""
26 @question.strip!
26 @question.strip!
27 @all_words = params[:all_words] || (params[:submit] ? false : true)
27 @all_words = params[:all_words] || (params[:submit] ? false : true)
28
28
29 offset = nil
30 begin; offset = params[:offset].to_time if params[:offset]; rescue; end
31
29 # quick jump to an issue
32 # quick jump to an issue
30 if @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(logged_in_user))
33 if @question.match(/^#?(\d+)$/) && Issue.find_by_id($1, :include => :project, :conditions => Project.visible_by(logged_in_user))
31 redirect_to :controller => "issues", :action => "show", :id => $1
34 redirect_to :controller => "issues", :action => "show", :id => $1
32 return
35 return
33 end
36 end
34
37
35 if params[:id]
38 if params[:id]
36 find_project
39 find_project
37 return unless check_project_privacy
40 return unless check_project_privacy
38 end
41 end
39
42
40 if @project
43 if @project
41 @object_types = %w(projects issues changesets news documents wiki_pages messages)
42 @object_types.delete('wiki_pages') unless @project.wiki
43 @object_types.delete('changesets') unless @project.repository
44 # only show what the user is allowed to view
44 # only show what the user is allowed to view
45 @object_types = %w(issues news documents changesets wiki_pages messages)
45 @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
46 @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, @project)}
46
47
47 @scope = @object_types.select {|t| params[t]}
48 @scope = @object_types.select {|t| params[t]}
48 # default objects to search if none is specified in parameters
49 @scope = @object_types if @scope.empty?
49 @scope = @object_types if @scope.empty?
50 else
50 else
51 @object_types = @scope = %w(projects)
51 @object_types = @scope = %w(projects)
52 end
52 end
53
53
54 # tokens must be at least 3 character long
54 # tokens must be at least 3 character long
55 @tokens = @question.split.uniq.select {|w| w.length > 2 }
55 @tokens = @question.split.uniq.select {|w| w.length > 2 }
56
56
57 if !@tokens.empty?
57 if !@tokens.empty?
58 # no more than 5 tokens to search for
58 # no more than 5 tokens to search for
59 @tokens.slice! 5..-1 if @tokens.size > 5
59 @tokens.slice! 5..-1 if @tokens.size > 5
60 # strings used in sql like statement
60 # strings used in sql like statement
61 like_tokens = @tokens.collect {|w| "%#{w.downcase}%"}
61 like_tokens = @tokens.collect {|w| "%#{w.downcase}%"}
62 operator = @all_words ? " AND " : " OR "
62 operator = @all_words ? " AND " : " OR "
63 limit = 10
64 @results = []
63 @results = []
64 limit = 10
65 if @project
65 if @project
66 @results += @project.issues.find(:all, :limit => limit, :include => :author, :conditions => [ (["(LOWER(subject) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'issues'
66 @scope.each do |s|
67 Journal.with_scope :find => {:conditions => ["#{Issue.table_name}.project_id = ?", @project.id]} do
67 @results += s.singularize.camelcase.constantize.search(like_tokens, @all_words, @project,
68 @results += Journal.find(:all, :include => :issue, :limit => limit, :conditions => [ (["(LOWER(notes) like ? OR LOWER(notes) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ).collect(&:issue) if @scope.include? 'issues'
68 :limit => (limit+1), :offset => offset, :before => params[:previous].nil?)
69 end
70 @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime}
71 if params[:previous].nil?
72 @pagination_previous_date = @results[0].event_datetime if offset && @results[0]
73 if @results.size > limit
74 @pagination_next_date = @results[limit-1].event_datetime
75 @results = @results[0, limit]
76 end
77 else
78 @pagination_next_date = @results[-1].event_datetime if offset && @results[-1]
79 if @results.size > limit
80 @pagination_previous_date = @results[-(limit)].event_datetime
81 @results = @results[-(limit), limit]
69 end
82 end
70 @results.uniq!
71 @results += @project.news.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort], :include => :author ) if @scope.include? 'news'
72 @results += @project.documents.find(:all, :limit => limit, :conditions => [ (["(LOWER(title) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'documents'
73 @results += @project.wiki.pages.find(:all, :limit => limit, :include => :content, :conditions => [ (["(LOWER(title) like ? OR LOWER(text) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @project.wiki && @scope.include?('wiki_pages')
74 @results += @project.repository.changesets.find(:all, :limit => limit, :conditions => [ (["(LOWER(comments) like ?)"] * like_tokens.size).join(operator), * (like_tokens).sort] ) if @project.repository && @scope.include?('changesets')
75 Message.with_scope :find => {:conditions => ["#{Board.table_name}.project_id = ?", @project.id]} do
76 @results += Message.find(:all, :include => :board, :limit => limit, :conditions => [ (["(LOWER(subject) like ? OR LOWER(content) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'messages'
77 end
83 end
78 else
84 else
79 Project.with_scope(:find => {:conditions => Project.visible_by(logged_in_user)}) do
85 Project.with_scope(:find => {:conditions => Project.visible_by(logged_in_user)}) do
80 @results += Project.find(:all, :limit => limit, :conditions => [ (["(LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'projects'
86 @results += Project.find(:all, :limit => limit, :conditions => [ (["(LOWER(name) like ? OR LOWER(description) like ?)"] * like_tokens.size).join(operator), * (like_tokens * 2).sort] ) if @scope.include? 'projects'
81 end
87 end
82 # if only one project is found, user is redirected to its overview
88 # if only one project is found, user is redirected to its overview
83 redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
89 redirect_to :controller => 'projects', :action => 'show', :id => @results.first and return if @results.size == 1
84 end
90 end
85 @question = @tokens.join(" ")
91 @question = @tokens.join(" ")
86 else
92 else
87 @question = ""
93 @question = ""
88 end
94 end
95 render :layout => false if request.xhr?
89 end
96 end
90
97
91 private
98 private
92 def find_project
99 def find_project
93 @project = Project.find(params[:id])
100 @project = Project.find(params[:id])
94 rescue ActiveRecord::RecordNotFound
101 rescue ActiveRecord::RecordNotFound
95 render_404
102 render_404
96 end
103 end
97 end
104 end
@@ -1,33 +1,33
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 module SearchHelper
18 module SearchHelper
19 def highlight_tokens(text, tokens)
19 def highlight_tokens(text, tokens)
20 return text unless tokens && !tokens.empty?
20 return text unless text && tokens && !tokens.empty?
21 regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
21 regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
22 result = ''
22 result = ''
23 text.split(regexp).each_with_index do |words, i|
23 text.split(regexp).each_with_index do |words, i|
24 if result.length > 1200
24 if result.length > 1200
25 # maximum length of the preview reached
25 # maximum length of the preview reached
26 result << '...'
26 result << '...'
27 break
27 break
28 end
28 end
29 result << (i.even? ? h(words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', h(words), :class => 'highlight'))
29 result << (i.even? ? h(words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', h(words), :class => 'highlight'))
30 end
30 end
31 result
31 result
32 end
32 end
33 end
33 end
@@ -1,79 +1,84
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Changeset < ActiveRecord::Base
18 class Changeset < ActiveRecord::Base
19 belongs_to :repository
19 belongs_to :repository
20 has_many :changes, :dependent => :delete_all
20 has_many :changes, :dependent => :delete_all
21 has_and_belongs_to_many :issues
21 has_and_belongs_to_many :issues
22
22
23 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.comments.blank? ? '' : (': ' + o.comments))},
23 acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.comments.blank? ? '' : (': ' + o.comments))},
24 :description => :comments,
24 :description => :comments,
25 :datetime => :committed_on,
25 :datetime => :committed_on,
26 :author => :committer,
26 :author => :committer,
27 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}}
27 :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}}
28
28
29 acts_as_searchable :columns => 'comments',
30 :include => :repository,
31 :project_key => "#{Repository.table_name}.project_id",
32 :date_column => 'committed_on'
33
29 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
34 validates_presence_of :repository_id, :revision, :committed_on, :commit_date
30 validates_numericality_of :revision, :only_integer => true
35 validates_numericality_of :revision, :only_integer => true
31 validates_uniqueness_of :revision, :scope => :repository_id
36 validates_uniqueness_of :revision, :scope => :repository_id
32 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
37 validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
33
38
34 def comments=(comment)
39 def comments=(comment)
35 write_attribute(:comments, comment.strip)
40 write_attribute(:comments, comment.strip)
36 end
41 end
37
42
38 def committed_on=(date)
43 def committed_on=(date)
39 self.commit_date = date
44 self.commit_date = date
40 super
45 super
41 end
46 end
42
47
43 def after_create
48 def after_create
44 scan_comment_for_issue_ids
49 scan_comment_for_issue_ids
45 end
50 end
46
51
47 def scan_comment_for_issue_ids
52 def scan_comment_for_issue_ids
48 return if comments.blank?
53 return if comments.blank?
49 # keywords used to reference issues
54 # keywords used to reference issues
50 ref_keywords = Setting.commit_ref_keywords.downcase.split(",")
55 ref_keywords = Setting.commit_ref_keywords.downcase.split(",")
51 # keywords used to fix issues
56 # keywords used to fix issues
52 fix_keywords = Setting.commit_fix_keywords.downcase.split(",")
57 fix_keywords = Setting.commit_fix_keywords.downcase.split(",")
53 # status applied
58 # status applied
54 fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
59 fix_status = IssueStatus.find_by_id(Setting.commit_fix_status_id)
55
60
56 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw.strip)}.join("|")
61 kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw.strip)}.join("|")
57 return if kw_regexp.blank?
62 return if kw_regexp.blank?
58
63
59 # remove any associated issues
64 # remove any associated issues
60 self.issues.clear
65 self.issues.clear
61
66
62 comments.scan(Regexp.new("(#{kw_regexp})[\s:]+(([\s,;&]*#?\\d+)+)", Regexp::IGNORECASE)).each do |match|
67 comments.scan(Regexp.new("(#{kw_regexp})[\s:]+(([\s,;&]*#?\\d+)+)", Regexp::IGNORECASE)).each do |match|
63 action = match[0]
68 action = match[0]
64 target_issue_ids = match[1].scan(/\d+/)
69 target_issue_ids = match[1].scan(/\d+/)
65 target_issues = repository.project.issues.find_all_by_id(target_issue_ids)
70 target_issues = repository.project.issues.find_all_by_id(target_issue_ids)
66 if fix_status && fix_keywords.include?(action.downcase)
71 if fix_status && fix_keywords.include?(action.downcase)
67 # update status of issues
72 # update status of issues
68 logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
73 logger.debug "Issues fixed by changeset #{self.revision}: #{issue_ids.join(', ')}." if logger && logger.debug?
69 target_issues.each do |issue|
74 target_issues.each do |issue|
70 # don't change the status is the issue is already closed
75 # don't change the status is the issue is already closed
71 next if issue.status.is_closed?
76 next if issue.status.is_closed?
72 issue.status = fix_status
77 issue.status = fix_status
73 issue.save
78 issue.save
74 end
79 end
75 end
80 end
76 self.issues << target_issues
81 self.issues << target_issues
77 end
82 end
78 end
83 end
79 end
84 end
@@ -1,27 +1,29
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Document < ActiveRecord::Base
18 class Document < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
20 belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
21 has_many :attachments, :as => :container, :dependent => :destroy
21 has_many :attachments, :as => :container, :dependent => :destroy
22
22
23 acts_as_event :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
23 acts_as_searchable :columns => ['title', 'description']
24 acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
25 :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}}
24
26
25 validates_presence_of :project, :title, :category
27 validates_presence_of :project, :title, :category
26 validates_length_of :title, :maximum => 60
28 validates_length_of :title, :maximum => 60
27 end
29 end
@@ -1,169 +1,170
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Issue < ActiveRecord::Base
18 class Issue < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :tracker
20 belongs_to :tracker
21 belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
21 belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
22 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
22 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
23 belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
23 belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
24 belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
24 belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
25 belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
25 belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
26 belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
26 belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
27
27
28 has_many :journals, :as => :journalized, :dependent => :destroy
28 has_many :journals, :as => :journalized, :dependent => :destroy
29 has_many :attachments, :as => :container, :dependent => :destroy
29 has_many :attachments, :as => :container, :dependent => :destroy
30 has_many :time_entries, :dependent => :nullify
30 has_many :time_entries, :dependent => :nullify
31 has_many :custom_values, :dependent => :delete_all, :as => :customized
31 has_many :custom_values, :dependent => :delete_all, :as => :customized
32 has_many :custom_fields, :through => :custom_values
32 has_many :custom_fields, :through => :custom_values
33 has_and_belongs_to_many :changesets, :order => "revision ASC"
33 has_and_belongs_to_many :changesets, :order => "revision ASC"
34
34
35 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
35 has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
36 has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
36 has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
37
37
38 acts_as_watchable
38 acts_as_watchable
39 acts_as_searchable :columns => ['subject', 'description'], :with => {:journal => :issue}
39 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
40 acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
40 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}
41 :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}
41
42
42 validates_presence_of :subject, :description, :priority, :tracker, :author, :status
43 validates_presence_of :subject, :description, :priority, :tracker, :author, :status
43 validates_length_of :subject, :maximum => 255
44 validates_length_of :subject, :maximum => 255
44 validates_inclusion_of :done_ratio, :in => 0..100
45 validates_inclusion_of :done_ratio, :in => 0..100
45 validates_numericality_of :estimated_hours, :allow_nil => true
46 validates_numericality_of :estimated_hours, :allow_nil => true
46 validates_associated :custom_values, :on => :update
47 validates_associated :custom_values, :on => :update
47
48
48 # set default status for new issues
49 # set default status for new issues
49 def before_validation
50 def before_validation
50 self.status = IssueStatus.default if status.nil?
51 self.status = IssueStatus.default if status.nil?
51 end
52 end
52
53
53 def validate
54 def validate
54 if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
55 if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
55 errors.add :due_date, :activerecord_error_not_a_date
56 errors.add :due_date, :activerecord_error_not_a_date
56 end
57 end
57
58
58 if self.due_date and self.start_date and self.due_date < self.start_date
59 if self.due_date and self.start_date and self.due_date < self.start_date
59 errors.add :due_date, :activerecord_error_greater_than_start_date
60 errors.add :due_date, :activerecord_error_greater_than_start_date
60 end
61 end
61
62
62 if start_date && soonest_start && start_date < soonest_start
63 if start_date && soonest_start && start_date < soonest_start
63 errors.add :start_date, :activerecord_error_invalid
64 errors.add :start_date, :activerecord_error_invalid
64 end
65 end
65
66
66 # validate assignment
67 # validate assignment
67 if assigned_to && !assignable_users.include?(assigned_to)
68 if assigned_to && !assignable_users.include?(assigned_to)
68 errors.add :assigned_to_id, :activerecord_error_invalid
69 errors.add :assigned_to_id, :activerecord_error_invalid
69 end
70 end
70 end
71 end
71
72
72 def before_create
73 def before_create
73 # default assignment based on category
74 # default assignment based on category
74 if assigned_to.nil? && category && category.assigned_to
75 if assigned_to.nil? && category && category.assigned_to
75 self.assigned_to = category.assigned_to
76 self.assigned_to = category.assigned_to
76 end
77 end
77 end
78 end
78
79
79 def before_save
80 def before_save
80 if @current_journal
81 if @current_journal
81 # attributes changes
82 # attributes changes
82 (Issue.column_names - %w(id description)).each {|c|
83 (Issue.column_names - %w(id description)).each {|c|
83 @current_journal.details << JournalDetail.new(:property => 'attr',
84 @current_journal.details << JournalDetail.new(:property => 'attr',
84 :prop_key => c,
85 :prop_key => c,
85 :old_value => @issue_before_change.send(c),
86 :old_value => @issue_before_change.send(c),
86 :value => send(c)) unless send(c)==@issue_before_change.send(c)
87 :value => send(c)) unless send(c)==@issue_before_change.send(c)
87 }
88 }
88 # custom fields changes
89 # custom fields changes
89 custom_values.each {|c|
90 custom_values.each {|c|
90 next if (@custom_values_before_change[c.custom_field_id]==c.value ||
91 next if (@custom_values_before_change[c.custom_field_id]==c.value ||
91 (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
92 (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?))
92 @current_journal.details << JournalDetail.new(:property => 'cf',
93 @current_journal.details << JournalDetail.new(:property => 'cf',
93 :prop_key => c.custom_field_id,
94 :prop_key => c.custom_field_id,
94 :old_value => @custom_values_before_change[c.custom_field_id],
95 :old_value => @custom_values_before_change[c.custom_field_id],
95 :value => c.value)
96 :value => c.value)
96 }
97 }
97 @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
98 @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
98 end
99 end
99 end
100 end
100
101
101 def after_save
102 def after_save
102 # Update start/due dates of following issues
103 # Update start/due dates of following issues
103 relations_from.each(&:set_issue_to_dates)
104 relations_from.each(&:set_issue_to_dates)
104
105
105 # Close duplicates if the issue was closed
106 # Close duplicates if the issue was closed
106 if @issue_before_change && !@issue_before_change.closed? && self.closed?
107 if @issue_before_change && !@issue_before_change.closed? && self.closed?
107 duplicates.each do |duplicate|
108 duplicates.each do |duplicate|
108 # Don't re-close it if it's already closed
109 # Don't re-close it if it's already closed
109 next if duplicate.closed?
110 next if duplicate.closed?
110 # Same user and notes
111 # Same user and notes
111 duplicate.init_journal(@current_journal.user, @current_journal.notes)
112 duplicate.init_journal(@current_journal.user, @current_journal.notes)
112 duplicate.update_attribute :status, self.status
113 duplicate.update_attribute :status, self.status
113 end
114 end
114 end
115 end
115 end
116 end
116
117
117 def custom_value_for(custom_field)
118 def custom_value_for(custom_field)
118 self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
119 self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
119 return nil
120 return nil
120 end
121 end
121
122
122 def init_journal(user, notes = "")
123 def init_journal(user, notes = "")
123 @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
124 @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
124 @issue_before_change = self.clone
125 @issue_before_change = self.clone
125 @custom_values_before_change = {}
126 @custom_values_before_change = {}
126 self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
127 self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
127 @current_journal
128 @current_journal
128 end
129 end
129
130
130 # Return true if the issue is closed, otherwise false
131 # Return true if the issue is closed, otherwise false
131 def closed?
132 def closed?
132 self.status.is_closed?
133 self.status.is_closed?
133 end
134 end
134
135
135 # Users the issue can be assigned to
136 # Users the issue can be assigned to
136 def assignable_users
137 def assignable_users
137 project.members.select {|m| m.role.assignable?}.collect {|m| m.user}
138 project.members.select {|m| m.role.assignable?}.collect {|m| m.user}
138 end
139 end
139
140
140 def spent_hours
141 def spent_hours
141 @spent_hours ||= time_entries.sum(:hours) || 0
142 @spent_hours ||= time_entries.sum(:hours) || 0
142 end
143 end
143
144
144 def relations
145 def relations
145 (relations_from + relations_to).sort
146 (relations_from + relations_to).sort
146 end
147 end
147
148
148 def all_dependent_issues
149 def all_dependent_issues
149 dependencies = []
150 dependencies = []
150 relations_from.each do |relation|
151 relations_from.each do |relation|
151 dependencies << relation.issue_to
152 dependencies << relation.issue_to
152 dependencies += relation.issue_to.all_dependent_issues
153 dependencies += relation.issue_to.all_dependent_issues
153 end
154 end
154 dependencies
155 dependencies
155 end
156 end
156
157
157 # Returns an array of the duplicate issues
158 # Returns an array of the duplicate issues
158 def duplicates
159 def duplicates
159 relations.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.other_issue(self)}
160 relations.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.other_issue(self)}
160 end
161 end
161
162
162 def duration
163 def duration
163 (start_date && due_date) ? due_date - start_date : 0
164 (start_date && due_date) ? due_date - start_date : 0
164 end
165 end
165
166
166 def soonest_start
167 def soonest_start
167 @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
168 @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
168 end
169 end
169 end
170 end
@@ -1,26 +1,31
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Journal < ActiveRecord::Base
18 class Journal < ActiveRecord::Base
19 belongs_to :journalized, :polymorphic => true
19 belongs_to :journalized, :polymorphic => true
20 # added as a quick fix to allow eager loading of the polymorphic association
20 # added as a quick fix to allow eager loading of the polymorphic association
21 # since always associated to an issue, for now
21 # since always associated to an issue, for now
22 belongs_to :issue, :foreign_key => :journalized_id
22 belongs_to :issue, :foreign_key => :journalized_id
23
23
24 belongs_to :user
24 belongs_to :user
25 has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
25 has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
26
27 acts_as_searchable :columns => 'notes',
28 :include => :issue,
29 :project_key => "#{Issue.table_name}.project_id",
30 :date_column => "#{Issue.table_name}.created_on"
26 end
31 end
@@ -1,41 +1,46
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Message < ActiveRecord::Base
18 class Message < ActiveRecord::Base
19 belongs_to :board
19 belongs_to :board
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
21 acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
22 has_many :attachments, :as => :container, :dependent => :destroy
22 has_many :attachments, :as => :container, :dependent => :destroy
23 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
23 belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
24
24
25 acts_as_searchable :columns => ['subject', 'content'], :include => :board, :project_key => "project_id"
26 acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
27 :description => :content,
28 :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id, :id => o.id}}
29
25 validates_presence_of :subject, :content
30 validates_presence_of :subject, :content
26 validates_length_of :subject, :maximum => 255
31 validates_length_of :subject, :maximum => 255
27
32
28 def after_create
33 def after_create
29 board.update_attribute(:last_message_id, self.id)
34 board.update_attribute(:last_message_id, self.id)
30 board.increment! :messages_count
35 board.increment! :messages_count
31 if parent
36 if parent
32 parent.reload.update_attribute(:last_reply_id, self.id)
37 parent.reload.update_attribute(:last_reply_id, self.id)
33 else
38 else
34 board.increment! :topics_count
39 board.increment! :topics_count
35 end
40 end
36 end
41 end
37
42
38 def project
43 def project
39 board.project
44 board.project
40 end
45 end
41 end
46 end
@@ -1,33 +1,34
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class News < ActiveRecord::Base
18 class News < ActiveRecord::Base
19 belongs_to :project
19 belongs_to :project
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
20 belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
21 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
21 has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
22
22
23 validates_presence_of :title, :description
23 validates_presence_of :title, :description
24 validates_length_of :title, :maximum => 60
24 validates_length_of :title, :maximum => 60
25 validates_length_of :summary, :maximum => 255
25 validates_length_of :summary, :maximum => 255
26
26
27 acts_as_searchable :columns => ['title', 'description']
27 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
28 acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
28
29
29 # returns latest news for projects visible by user
30 # returns latest news for projects visible by user
30 def self.latest(user=nil, count=5)
31 def self.latest(user=nil, count=5)
31 find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
32 find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
32 end
33 end
33 end
34 end
@@ -1,164 +1,168
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006 Jean-Philippe Lang
2 # Copyright (C) 2006 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 class Project < ActiveRecord::Base
18 class Project < ActiveRecord::Base
19 # Project statuses
19 # Project statuses
20 STATUS_ACTIVE = 1
20 STATUS_ACTIVE = 1
21 STATUS_ARCHIVED = 9
21 STATUS_ARCHIVED = 9
22
22
23 has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
23 has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}"
24 has_many :users, :through => :members
24 has_many :users, :through => :members
25 has_many :custom_values, :dependent => :delete_all, :as => :customized
25 has_many :custom_values, :dependent => :delete_all, :as => :customized
26 has_many :enabled_modules, :dependent => :delete_all
26 has_many :enabled_modules, :dependent => :delete_all
27 has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
27 has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker]
28 has_many :issue_changes, :through => :issues, :source => :journals
28 has_many :issue_changes, :through => :issues, :source => :journals
29 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
29 has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC"
30 has_many :time_entries, :dependent => :delete_all
30 has_many :time_entries, :dependent => :delete_all
31 has_many :queries, :dependent => :delete_all
31 has_many :queries, :dependent => :delete_all
32 has_many :documents, :dependent => :destroy
32 has_many :documents, :dependent => :destroy
33 has_many :news, :dependent => :delete_all, :include => :author
33 has_many :news, :dependent => :delete_all, :include => :author
34 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
34 has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
35 has_many :boards, :order => "position ASC"
35 has_many :boards, :order => "position ASC"
36 has_one :repository, :dependent => :destroy
36 has_one :repository, :dependent => :destroy
37 has_many :changesets, :through => :repository
37 has_many :changesets, :through => :repository
38 has_one :wiki, :dependent => :destroy
38 has_one :wiki, :dependent => :destroy
39 has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id'
39 has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id'
40 acts_as_tree :order => "name", :counter_cache => true
40 acts_as_tree :order => "name", :counter_cache => true
41
41
42 acts_as_searchable :columns => ['name', 'description'], :project_key => 'id'
43 acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"},
44 :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o.id}}
45
42 attr_protected :status, :enabled_module_names
46 attr_protected :status, :enabled_module_names
43
47
44 validates_presence_of :name, :description, :identifier
48 validates_presence_of :name, :description, :identifier
45 validates_uniqueness_of :name, :identifier
49 validates_uniqueness_of :name, :identifier
46 validates_associated :custom_values, :on => :update
50 validates_associated :custom_values, :on => :update
47 validates_associated :repository, :wiki
51 validates_associated :repository, :wiki
48 validates_length_of :name, :maximum => 30
52 validates_length_of :name, :maximum => 30
49 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
53 validates_format_of :name, :with => /^[\w\s\'\-]*$/i
50 validates_length_of :description, :maximum => 255
54 validates_length_of :description, :maximum => 255
51 validates_length_of :homepage, :maximum => 60
55 validates_length_of :homepage, :maximum => 60
52 validates_length_of :identifier, :in => 3..12
56 validates_length_of :identifier, :in => 3..12
53 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
57 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
54
58
55 def identifier=(identifier)
59 def identifier=(identifier)
56 super unless identifier_frozen?
60 super unless identifier_frozen?
57 end
61 end
58
62
59 def identifier_frozen?
63 def identifier_frozen?
60 errors[:identifier].nil? && !(new_record? || identifier.blank?)
64 errors[:identifier].nil? && !(new_record? || identifier.blank?)
61 end
65 end
62
66
63 def issues_with_subprojects(include_subprojects=false)
67 def issues_with_subprojects(include_subprojects=false)
64 conditions = nil
68 conditions = nil
65 if include_subprojects && !active_children.empty?
69 if include_subprojects && !active_children.empty?
66 ids = [id] + active_children.collect {|c| c.id}
70 ids = [id] + active_children.collect {|c| c.id}
67 conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
71 conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
68 end
72 end
69 conditions ||= ["#{Issue.table_name}.project_id = ?", id]
73 conditions ||= ["#{Issue.table_name}.project_id = ?", id]
70 Issue.with_scope :find => { :conditions => conditions } do
74 Issue.with_scope :find => { :conditions => conditions } do
71 yield
75 yield
72 end
76 end
73 end
77 end
74
78
75 # returns latest created projects
79 # returns latest created projects
76 # non public projects will be returned only if user is a member of those
80 # non public projects will be returned only if user is a member of those
77 def self.latest(user=nil, count=5)
81 def self.latest(user=nil, count=5)
78 find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
82 find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC")
79 end
83 end
80
84
81 def self.visible_by(user=nil)
85 def self.visible_by(user=nil)
82 if user && user.admin?
86 if user && user.admin?
83 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
87 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}"
84 elsif user && user.memberships.any?
88 elsif user && user.memberships.any?
85 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))"
89 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND (#{Project.table_name}.is_public = #{connection.quoted_true} or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')}))"
86 else
90 else
87 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
91 return "#{Project.table_name}.status=#{Project::STATUS_ACTIVE} AND #{Project.table_name}.is_public = #{connection.quoted_true}"
88 end
92 end
89 end
93 end
90
94
91 def active?
95 def active?
92 self.status == STATUS_ACTIVE
96 self.status == STATUS_ACTIVE
93 end
97 end
94
98
95 def archive
99 def archive
96 # Archive subprojects if any
100 # Archive subprojects if any
97 children.each do |subproject|
101 children.each do |subproject|
98 subproject.archive
102 subproject.archive
99 end
103 end
100 update_attribute :status, STATUS_ARCHIVED
104 update_attribute :status, STATUS_ARCHIVED
101 end
105 end
102
106
103 def unarchive
107 def unarchive
104 return false if parent && !parent.active?
108 return false if parent && !parent.active?
105 update_attribute :status, STATUS_ACTIVE
109 update_attribute :status, STATUS_ACTIVE
106 end
110 end
107
111
108 def active_children
112 def active_children
109 children.select {|child| child.active?}
113 children.select {|child| child.active?}
110 end
114 end
111
115
112 # Returns an array of all custom fields enabled for project issues
116 # Returns an array of all custom fields enabled for project issues
113 # (explictly associated custom fields and custom fields enabled for all projects)
117 # (explictly associated custom fields and custom fields enabled for all projects)
114 def custom_fields_for_issues(tracker)
118 def custom_fields_for_issues(tracker)
115 all_custom_fields.select {|c| tracker.custom_fields.include? c }
119 all_custom_fields.select {|c| tracker.custom_fields.include? c }
116 end
120 end
117
121
118 def all_custom_fields
122 def all_custom_fields
119 @all_custom_fields ||= (IssueCustomField.for_all + custom_fields).uniq
123 @all_custom_fields ||= (IssueCustomField.for_all + custom_fields).uniq
120 end
124 end
121
125
122 def <=>(project)
126 def <=>(project)
123 name <=> project.name
127 name <=> project.name
124 end
128 end
125
129
126 def allows_to?(action)
130 def allows_to?(action)
127 if action.is_a? Hash
131 if action.is_a? Hash
128 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
132 allowed_actions.include? "#{action[:controller]}/#{action[:action]}"
129 else
133 else
130 allowed_permissions.include? action
134 allowed_permissions.include? action
131 end
135 end
132 end
136 end
133
137
134 def module_enabled?(module_name)
138 def module_enabled?(module_name)
135 module_name = module_name.to_s
139 module_name = module_name.to_s
136 enabled_modules.detect {|m| m.name == module_name}
140 enabled_modules.detect {|m| m.name == module_name}
137 end
141 end
138
142
139 def enabled_module_names=(module_names)
143 def enabled_module_names=(module_names)
140 enabled_modules.clear
144 enabled_modules.clear
141 module_names = [] unless module_names && module_names.is_a?(Array)
145 module_names = [] unless module_names && module_names.is_a?(Array)
142 module_names.each do |name|
146 module_names.each do |name|
143 enabled_modules << EnabledModule.new(:name => name.to_s)
147 enabled_modules << EnabledModule.new(:name => name.to_s)
144 end
148 end
145 end
149 end
146
150
147 protected
151 protected
148 def validate
152 def validate
149 errors.add(parent_id, " must be a root project") if parent and parent.parent
153 errors.add(parent_id, " must be a root project") if parent and parent.parent
150 errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
154 errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
151 end
155 end
152
156
153 private
157 private
154 def allowed_permissions
158 def allowed_permissions
155 @allowed_permissions ||= begin
159 @allowed_permissions ||= begin
156 module_names = enabled_modules.collect {|m| m.name}
160 module_names = enabled_modules.collect {|m| m.name}
157 Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
161 Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name}
158 end
162 end
159 end
163 end
160
164
161 def allowed_actions
165 def allowed_actions
162 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
166 @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten
163 end
167 end
164 end
168 end
@@ -1,102 +1,115
1 # redMine - project management software
1 # redMine - project management software
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
2 # Copyright (C) 2006-2007 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require 'diff'
18 require 'diff'
19
19
20 class WikiPage < ActiveRecord::Base
20 class WikiPage < ActiveRecord::Base
21 belongs_to :wiki
21 belongs_to :wiki
22 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
22 has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
23 has_many :attachments, :as => :container, :dependent => :destroy
23 has_many :attachments, :as => :container, :dependent => :destroy
24
24
25 acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
26 :description => :text,
27 :datetime => :created_on,
28 :url => Proc.new {|o| {:controller => 'wiki', :id => o.wiki.project_id, :page => o.title}}
29
30 acts_as_searchable :columns => ['title', 'text'],
31 :include => [:wiki, :content],
32 :project_key => "#{Wiki.table_name}.project_id"
33
25 attr_accessor :redirect_existing_links
34 attr_accessor :redirect_existing_links
26
35
27 validates_presence_of :title
36 validates_presence_of :title
28 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
37 validates_format_of :title, :with => /^[^,\.\/\?\;\|\s]*$/
29 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
38 validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
30 validates_associated :content
39 validates_associated :content
31
40
32 def title=(value)
41 def title=(value)
33 value = Wiki.titleize(value)
42 value = Wiki.titleize(value)
34 @previous_title = read_attribute(:title) if @previous_title.blank?
43 @previous_title = read_attribute(:title) if @previous_title.blank?
35 write_attribute(:title, value)
44 write_attribute(:title, value)
36 end
45 end
37
46
38 def before_save
47 def before_save
39 self.title = Wiki.titleize(title)
48 self.title = Wiki.titleize(title)
40 # Manage redirects if the title has changed
49 # Manage redirects if the title has changed
41 if !@previous_title.blank? && (@previous_title != title) && !new_record?
50 if !@previous_title.blank? && (@previous_title != title) && !new_record?
42 # Update redirects that point to the old title
51 # Update redirects that point to the old title
43 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
52 wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r|
44 r.redirects_to = title
53 r.redirects_to = title
45 r.title == r.redirects_to ? r.destroy : r.save
54 r.title == r.redirects_to ? r.destroy : r.save
46 end
55 end
47 # Remove redirects for the new title
56 # Remove redirects for the new title
48 wiki.redirects.find_all_by_title(title).each(&:destroy)
57 wiki.redirects.find_all_by_title(title).each(&:destroy)
49 # Create a redirect to the new title
58 # Create a redirect to the new title
50 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
59 wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0"
51 @previous_title = nil
60 @previous_title = nil
52 end
61 end
53 end
62 end
54
63
55 def before_destroy
64 def before_destroy
56 # Remove redirects to this page
65 # Remove redirects to this page
57 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
66 wiki.redirects.find_all_by_redirects_to(title).each(&:destroy)
58 end
67 end
59
68
60 def pretty_title
69 def pretty_title
61 WikiPage.pretty_title(title)
70 WikiPage.pretty_title(title)
62 end
71 end
63
72
64 def content_for_version(version=nil)
73 def content_for_version(version=nil)
65 result = content.versions.find_by_version(version.to_i) if version
74 result = content.versions.find_by_version(version.to_i) if version
66 result ||= content
75 result ||= content
67 result
76 result
68 end
77 end
69
78
70 def diff(version_to=nil, version_from=nil)
79 def diff(version_to=nil, version_from=nil)
71 version_to = version_to ? version_to.to_i : self.content.version
80 version_to = version_to ? version_to.to_i : self.content.version
72 version_from = version_from ? version_from.to_i : version_to - 1
81 version_from = version_from ? version_from.to_i : version_to - 1
73 version_to, version_from = version_from, version_to unless version_from < version_to
82 version_to, version_from = version_from, version_to unless version_from < version_to
74
83
75 content_to = content.versions.find_by_version(version_to)
84 content_to = content.versions.find_by_version(version_to)
76 content_from = content.versions.find_by_version(version_from)
85 content_from = content.versions.find_by_version(version_from)
77
86
78 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
87 (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil
79 end
88 end
80
89
81 def self.pretty_title(str)
90 def self.pretty_title(str)
82 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
91 (str && str.is_a?(String)) ? str.tr('_', ' ') : str
83 end
92 end
84
93
85 def project
94 def project
86 wiki.project
95 wiki.project
87 end
96 end
97
98 def text
99 content.text if content
100 end
88 end
101 end
89
102
90 class WikiDiff
103 class WikiDiff
91 attr_reader :diff, :words, :content_to, :content_from
104 attr_reader :diff, :words, :content_to, :content_from
92
105
93 def initialize(content_to, content_from)
106 def initialize(content_to, content_from)
94 @content_to = content_to
107 @content_to = content_to
95 @content_from = content_from
108 @content_from = content_from
96 @words = content_to.text.split(/(\s+)/)
109 @words = content_to.text.split(/(\s+)/)
97 @words = @words.select {|word| word != ' '}
110 @words = @words.select {|word| word != ' '}
98 words_from = content_from.text.split(/(\s+)/)
111 words_from = content_from.text.split(/(\s+)/)
99 words_from = words_from.select {|word| word != ' '}
112 words_from = words_from.select {|word| word != ' '}
100 @diff = words_from.diff @words
113 @diff = words_from.diff @words
101 end
114 end
102 end
115 end
@@ -1,53 +1,41
1 <h2><%= l(:label_search) %></h2>
1 <h2><%= l(:label_search) %></h2>
2
2
3 <div class="box">
3 <div class="box">
4 <% form_tag({}, :method => :get) do %>
4 <% form_tag({}, :method => :get) do %>
5 <p><%= text_field_tag 'q', @question, :size => 30, :id => 'search-input' %>
5 <p><%= text_field_tag 'q', @question, :size => 30, :id => 'search-input' %>
6 <%= javascript_tag "Field.focus('search-input')" %>
6 <%= javascript_tag "Field.focus('search-input')" %>
7
7
8 <% @object_types.each do |t| %>
8 <% @object_types.each do |t| %>
9 <label><%= check_box_tag t, 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label>
9 <label><%= check_box_tag t, 1, @scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label>
10 <% end %>
10 <% end %>
11 <br />
11 <br />
12 <%= check_box_tag 'all_words', 1, @all_words %> <%= l(:label_all_words) %></p>
12 <%= check_box_tag 'all_words', 1, @all_words %> <%= l(:label_all_words) %></p>
13 <%= submit_tag l(:button_submit), :name => 'submit' %>
13 <%= submit_tag l(:button_submit), :name => 'submit' %>
14 <% end %>
14 <% end %>
15 </div>
15 </div>
16
16
17 <% if @results %>
17 <% if @results %>
18 <h3><%= lwr(:label_result, @results.length) %></h3>
18 <h3><%= l(:label_result_plural) %></h3>
19 <ul>
19 <ul>
20 <% @results.each do |e| %>
20 <% @results.each do |e| %>
21 <li><p>
21 <li><p><%= link_to highlight_tokens(truncate(e.event_title, 255), @tokens), e.event_url %><br />
22 <% if e.is_a? Project %>
22 <%= highlight_tokens(e.event_description, @tokens) %><br />
23 <%= link_to highlight_tokens(h(e.name), @tokens), :controller => 'projects', :action => 'show', :id => e %><br />
23 <span class="author"><%= format_time(e.event_datetime) %></span></p></li>
24 <%= highlight_tokens(e.description, @tokens) %>
25 <% elsif e.is_a? Issue %>
26 <%= link_to_issue e %>: <%= highlight_tokens(h(e.subject), @tokens) %><br />
27 <%= highlight_tokens(e.description, @tokens) %><br />
28 <i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
29 <% elsif e.is_a? News %>
30 <%=l(:label_news)%>: <%= link_to highlight_tokens(h(e.title), @tokens), :controller => 'news', :action => 'show', :id => e %><br />
31 <%= highlight_tokens(e.description, @tokens) %><br />
32 <i><%= e.author.name %>, <%= format_time(e.created_on) %></i>
33 <% elsif e.is_a? Document %>
34 <%=l(:label_document)%>: <%= link_to highlight_tokens(h(e.title), @tokens), :controller => 'documents', :action => 'show', :id => e %><br />
35 <%= highlight_tokens(e.description, @tokens) %><br />
36 <i><%= format_time(e.created_on) %></i>
37 <% elsif e.is_a? WikiPage %>
38 <%=l(:label_wiki)%>: <%= link_to highlight_tokens(h(e.pretty_title), @tokens), :controller => 'wiki', :action => 'index', :id => @project, :page => e.title %><br />
39 <%= highlight_tokens(e.content.text, @tokens) %><br />
40 <i><%= e.content.author ? e.content.author.name : "Anonymous" %>, <%= format_time(e.content.updated_on) %></i>
41 <% elsif e.is_a? Changeset %>
42 <%=l(:label_revision)%> <%= link_to h(e.revision), :controller => 'repositories', :action => 'revision', :id => @project, :rev => e.revision %><br />
43 <%= highlight_tokens(e.comments, @tokens) %><br />
44 <em><%= e.committer.blank? ? e.committer : "Anonymous" %>, <%= format_time(e.committed_on) %></em>
45 <% elsif e.is_a? Message %>
46 <%=h e.board.name %>: <%= link_to_message e %><br />
47 <%= highlight_tokens(e.content, @tokens) %><br />
48 <em><%= e.author ? e.author.name : "Anonymous" %>, <%= format_time(e.created_on) %></em>
49 <% end %>
50 </p></li>
51 <% end %>
24 <% end %>
52 </ul>
25 </ul>
53 <% end %>
26 <% end %>
27
28 <p><center>
29 <% if @pagination_previous_date %>
30 <%= link_to_remote ('&#171; ' + l(:label_previous)),
31 {:update => :content,
32 :url => params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))
33 }, :href => url_for(params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>&nbsp;
34 <% end %>
35 <% if @pagination_next_date %>
36 <%= link_to_remote (l(:label_next) + ' &#187;'),
37 {:update => :content,
38 :url => params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))
39 }, :href => url_for(params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %>
40 <% end %>
41 </center></p>
@@ -1,91 +1,93
1 # Be sure to restart your web server when you modify this file.
1 # Be sure to restart your web server when you modify this file.
2
2
3 # Uncomment below to force Rails into production mode when
3 # Uncomment below to force Rails into production mode when
4 # you don't control web/app server and can't set it the proper way
4 # you don't control web/app server and can't set it the proper way
5 # ENV['RAILS_ENV'] ||= 'production'
5 # ENV['RAILS_ENV'] ||= 'production'
6
6
7 # Bootstrap the Rails environment, frameworks, and default configuration
7 # Bootstrap the Rails environment, frameworks, and default configuration
8 require File.join(File.dirname(__FILE__), 'boot')
8 require File.join(File.dirname(__FILE__), 'boot')
9
9
10 Rails::Initializer.run do |config|
10 Rails::Initializer.run do |config|
11 # Settings in config/environments/* take precedence those specified here
11 # Settings in config/environments/* take precedence those specified here
12
12
13 # Skip frameworks you're not going to use
13 # Skip frameworks you're not going to use
14 # config.frameworks -= [ :action_web_service, :action_mailer ]
14 # config.frameworks -= [ :action_web_service, :action_mailer ]
15
15
16 # Add additional load paths for sweepers
16 # Add additional load paths for sweepers
17 config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )
17 config.load_paths += %W( #{RAILS_ROOT}/app/sweepers )
18
18
19 config.plugin_paths = ['lib/plugins', 'vendor/plugins']
20
19 # Force all environments to use the same logger level
21 # Force all environments to use the same logger level
20 # (by default production uses :info, the others :debug)
22 # (by default production uses :info, the others :debug)
21 # config.log_level = :debug
23 # config.log_level = :debug
22
24
23 # Use the database for sessions instead of the file system
25 # Use the database for sessions instead of the file system
24 # (create the session table with 'rake create_sessions_table')
26 # (create the session table with 'rake create_sessions_table')
25 # config.action_controller.session_store = :active_record_store
27 # config.action_controller.session_store = :active_record_store
26
28
27 # Enable page/fragment caching by setting a file-based store
29 # Enable page/fragment caching by setting a file-based store
28 # (remember to create the caching directory and make it readable to the application)
30 # (remember to create the caching directory and make it readable to the application)
29 # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
31 # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache"
30
32
31 # Activate observers that should always be running
33 # Activate observers that should always be running
32 # config.active_record.observers = :cacher, :garbage_collector
34 # config.active_record.observers = :cacher, :garbage_collector
33 config.active_record.observers = :message_observer
35 config.active_record.observers = :message_observer
34
36
35 # Make Active Record use UTC-base instead of local time
37 # Make Active Record use UTC-base instead of local time
36 # config.active_record.default_timezone = :utc
38 # config.active_record.default_timezone = :utc
37
39
38 # Use Active Record's schema dumper instead of SQL when creating the test database
40 # Use Active Record's schema dumper instead of SQL when creating the test database
39 # (enables use of different database adapters for development and test environments)
41 # (enables use of different database adapters for development and test environments)
40 # config.active_record.schema_format = :ruby
42 # config.active_record.schema_format = :ruby
41
43
42 # See Rails::Configuration for more options
44 # See Rails::Configuration for more options
43
45
44 # SMTP server configuration
46 # SMTP server configuration
45 config.action_mailer.smtp_settings = {
47 config.action_mailer.smtp_settings = {
46 :address => "127.0.0.1",
48 :address => "127.0.0.1",
47 :port => 25,
49 :port => 25,
48 :domain => "somenet.foo",
50 :domain => "somenet.foo",
49 :authentication => :login,
51 :authentication => :login,
50 :user_name => "redmine",
52 :user_name => "redmine",
51 :password => "redmine",
53 :password => "redmine",
52 }
54 }
53
55
54 config.action_mailer.perform_deliveries = true
56 config.action_mailer.perform_deliveries = true
55
57
56 # Tell ActionMailer not to deliver emails to the real world.
58 # Tell ActionMailer not to deliver emails to the real world.
57 # The :test delivery method accumulates sent emails in the
59 # The :test delivery method accumulates sent emails in the
58 # ActionMailer::Base.deliveries array.
60 # ActionMailer::Base.deliveries array.
59 #config.action_mailer.delivery_method = :test
61 #config.action_mailer.delivery_method = :test
60 config.action_mailer.delivery_method = :smtp
62 config.action_mailer.delivery_method = :smtp
61
63
62 # Uncomment this line if the engines plugin is installed.
64 # Uncomment this line if the engines plugin is installed.
63 # This will ensure that engines is loaded first.
65 # This will ensure that engines is loaded first.
64 # config.plugins = ["engines", "*"]
66 # config.plugins = ["engines", "*"]
65 end
67 end
66
68
67 ActiveRecord::Errors.default_error_messages = {
69 ActiveRecord::Errors.default_error_messages = {
68 :inclusion => "activerecord_error_inclusion",
70 :inclusion => "activerecord_error_inclusion",
69 :exclusion => "activerecord_error_exclusion",
71 :exclusion => "activerecord_error_exclusion",
70 :invalid => "activerecord_error_invalid",
72 :invalid => "activerecord_error_invalid",
71 :confirmation => "activerecord_error_confirmation",
73 :confirmation => "activerecord_error_confirmation",
72 :accepted => "activerecord_error_accepted",
74 :accepted => "activerecord_error_accepted",
73 :empty => "activerecord_error_empty",
75 :empty => "activerecord_error_empty",
74 :blank => "activerecord_error_blank",
76 :blank => "activerecord_error_blank",
75 :too_long => "activerecord_error_too_long",
77 :too_long => "activerecord_error_too_long",
76 :too_short => "activerecord_error_too_short",
78 :too_short => "activerecord_error_too_short",
77 :wrong_length => "activerecord_error_wrong_length",
79 :wrong_length => "activerecord_error_wrong_length",
78 :taken => "activerecord_error_taken",
80 :taken => "activerecord_error_taken",
79 :not_a_number => "activerecord_error_not_a_number"
81 :not_a_number => "activerecord_error_not_a_number"
80 }
82 }
81
83
82 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
84 ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" }
83
85
84 GLoc.set_config :default_language => :en
86 GLoc.set_config :default_language => :en
85 GLoc.clear_strings
87 GLoc.clear_strings
86 GLoc.set_kcode
88 GLoc.set_kcode
87 GLoc.load_localized_strings
89 GLoc.load_localized_strings
88 GLoc.set_config(:raise_string_not_found_errors => false)
90 GLoc.set_config(:raise_string_not_found_errors => false)
89
91
90 require 'redmine'
92 require 'redmine'
91
93
@@ -1,513 +1,512
1 _gloc_rule_default: '|n| n==1 ? "" : "_plural" '
1 _gloc_rule_default: '|n| n==1 ? "" : "_plural" '
2
2
3 actionview_datehelper_select_day_prefix:
3 actionview_datehelper_select_day_prefix:
4 actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December
4 actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December
5 actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
5 actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
6 actionview_datehelper_select_month_prefix:
6 actionview_datehelper_select_month_prefix:
7 actionview_datehelper_select_year_prefix:
7 actionview_datehelper_select_year_prefix:
8 actionview_datehelper_time_in_words_day: 1 day
8 actionview_datehelper_time_in_words_day: 1 day
9 actionview_datehelper_time_in_words_day_plural: %d days
9 actionview_datehelper_time_in_words_day_plural: %d days
10 actionview_datehelper_time_in_words_hour_about: about an hour
10 actionview_datehelper_time_in_words_hour_about: about an hour
11 actionview_datehelper_time_in_words_hour_about_plural: about %d hours
11 actionview_datehelper_time_in_words_hour_about_plural: about %d hours
12 actionview_datehelper_time_in_words_hour_about_single: about an hour
12 actionview_datehelper_time_in_words_hour_about_single: about an hour
13 actionview_datehelper_time_in_words_minute: 1 minute
13 actionview_datehelper_time_in_words_minute: 1 minute
14 actionview_datehelper_time_in_words_minute_half: half a minute
14 actionview_datehelper_time_in_words_minute_half: half a minute
15 actionview_datehelper_time_in_words_minute_less_than: less than a minute
15 actionview_datehelper_time_in_words_minute_less_than: less than a minute
16 actionview_datehelper_time_in_words_minute_plural: %d minutes
16 actionview_datehelper_time_in_words_minute_plural: %d minutes
17 actionview_datehelper_time_in_words_minute_single: 1 minute
17 actionview_datehelper_time_in_words_minute_single: 1 minute
18 actionview_datehelper_time_in_words_second_less_than: less than a second
18 actionview_datehelper_time_in_words_second_less_than: less than a second
19 actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds
19 actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds
20 actionview_instancetag_blank_option: Please select
20 actionview_instancetag_blank_option: Please select
21
21
22 activerecord_error_inclusion: is not included in the list
22 activerecord_error_inclusion: is not included in the list
23 activerecord_error_exclusion: is reserved
23 activerecord_error_exclusion: is reserved
24 activerecord_error_invalid: is invalid
24 activerecord_error_invalid: is invalid
25 activerecord_error_confirmation: doesn't match confirmation
25 activerecord_error_confirmation: doesn't match confirmation
26 activerecord_error_accepted: must be accepted
26 activerecord_error_accepted: must be accepted
27 activerecord_error_empty: can't be empty
27 activerecord_error_empty: can't be empty
28 activerecord_error_blank: can't be blank
28 activerecord_error_blank: can't be blank
29 activerecord_error_too_long: is too long
29 activerecord_error_too_long: is too long
30 activerecord_error_too_short: is too short
30 activerecord_error_too_short: is too short
31 activerecord_error_wrong_length: is the wrong length
31 activerecord_error_wrong_length: is the wrong length
32 activerecord_error_taken: has already been taken
32 activerecord_error_taken: has already been taken
33 activerecord_error_not_a_number: is not a number
33 activerecord_error_not_a_number: is not a number
34 activerecord_error_not_a_date: is not a valid date
34 activerecord_error_not_a_date: is not a valid date
35 activerecord_error_greater_than_start_date: must be greater than start date
35 activerecord_error_greater_than_start_date: must be greater than start date
36 activerecord_error_not_same_project: doesn't belong to the same project
36 activerecord_error_not_same_project: doesn't belong to the same project
37 activerecord_error_circular_dependency: This relation would create a circular dependency
37 activerecord_error_circular_dependency: This relation would create a circular dependency
38
38
39 general_fmt_age: %d yr
39 general_fmt_age: %d yr
40 general_fmt_age_plural: %d yrs
40 general_fmt_age_plural: %d yrs
41 general_fmt_date: %%m/%%d/%%Y
41 general_fmt_date: %%m/%%d/%%Y
42 general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p
42 general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p
43 general_fmt_datetime_short: %%b %%d, %%I:%%M %%p
43 general_fmt_datetime_short: %%b %%d, %%I:%%M %%p
44 general_fmt_time: %%I:%%M %%p
44 general_fmt_time: %%I:%%M %%p
45 general_text_No: 'No'
45 general_text_No: 'No'
46 general_text_Yes: 'Yes'
46 general_text_Yes: 'Yes'
47 general_text_no: 'no'
47 general_text_no: 'no'
48 general_text_yes: 'yes'
48 general_text_yes: 'yes'
49 general_lang_name: 'English'
49 general_lang_name: 'English'
50 general_csv_separator: ','
50 general_csv_separator: ','
51 general_csv_encoding: ISO-8859-1
51 general_csv_encoding: ISO-8859-1
52 general_pdf_encoding: ISO-8859-1
52 general_pdf_encoding: ISO-8859-1
53 general_day_names: Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
53 general_day_names: Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday
54
54
55 notice_account_updated: Account was successfully updated.
55 notice_account_updated: Account was successfully updated.
56 notice_account_invalid_creditentials: Invalid user or password
56 notice_account_invalid_creditentials: Invalid user or password
57 notice_account_password_updated: Password was successfully updated.
57 notice_account_password_updated: Password was successfully updated.
58 notice_account_wrong_password: Wrong password
58 notice_account_wrong_password: Wrong password
59 notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you.
59 notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you.
60 notice_account_unknown_email: Unknown user.
60 notice_account_unknown_email: Unknown user.
61 notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password.
61 notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password.
62 notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you.
62 notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you.
63 notice_account_activated: Your account has been activated. You can now log in.
63 notice_account_activated: Your account has been activated. You can now log in.
64 notice_successful_create: Successful creation.
64 notice_successful_create: Successful creation.
65 notice_successful_update: Successful update.
65 notice_successful_update: Successful update.
66 notice_successful_delete: Successful deletion.
66 notice_successful_delete: Successful deletion.
67 notice_successful_connection: Successful connection.
67 notice_successful_connection: Successful connection.
68 notice_file_not_found: The page you were trying to access doesn't exist or has been removed.
68 notice_file_not_found: The page you were trying to access doesn't exist or has been removed.
69 notice_locking_conflict: Data have been updated by another user.
69 notice_locking_conflict: Data have been updated by another user.
70 notice_scm_error: Entry and/or revision doesn't exist in the repository.
70 notice_scm_error: Entry and/or revision doesn't exist in the repository.
71 notice_not_authorized: You are not authorized to access this page.
71 notice_not_authorized: You are not authorized to access this page.
72 notice_email_sent: An email was sent to %s
72 notice_email_sent: An email was sent to %s
73 notice_email_error: An error occurred while sending mail (%s)
73 notice_email_error: An error occurred while sending mail (%s)
74 notice_feeds_access_key_reseted: Your RSS access key was reseted.
74 notice_feeds_access_key_reseted: Your RSS access key was reseted.
75
75
76 mail_subject_lost_password: Your redMine password
76 mail_subject_lost_password: Your redMine password
77 mail_subject_register: redMine account activation
77 mail_subject_register: redMine account activation
78
78
79 gui_validation_error: 1 error
79 gui_validation_error: 1 error
80 gui_validation_error_plural: %d errors
80 gui_validation_error_plural: %d errors
81
81
82 field_name: Name
82 field_name: Name
83 field_description: Description
83 field_description: Description
84 field_summary: Summary
84 field_summary: Summary
85 field_is_required: Required
85 field_is_required: Required
86 field_firstname: Firstname
86 field_firstname: Firstname
87 field_lastname: Lastname
87 field_lastname: Lastname
88 field_mail: Email
88 field_mail: Email
89 field_filename: File
89 field_filename: File
90 field_filesize: Size
90 field_filesize: Size
91 field_downloads: Downloads
91 field_downloads: Downloads
92 field_author: Author
92 field_author: Author
93 field_created_on: Created
93 field_created_on: Created
94 field_updated_on: Updated
94 field_updated_on: Updated
95 field_field_format: Format
95 field_field_format: Format
96 field_is_for_all: For all projects
96 field_is_for_all: For all projects
97 field_possible_values: Possible values
97 field_possible_values: Possible values
98 field_regexp: Regular expression
98 field_regexp: Regular expression
99 field_min_length: Minimum length
99 field_min_length: Minimum length
100 field_max_length: Maximum length
100 field_max_length: Maximum length
101 field_value: Value
101 field_value: Value
102 field_category: Category
102 field_category: Category
103 field_title: Title
103 field_title: Title
104 field_project: Project
104 field_project: Project
105 field_issue: Issue
105 field_issue: Issue
106 field_status: Status
106 field_status: Status
107 field_notes: Notes
107 field_notes: Notes
108 field_is_closed: Issue closed
108 field_is_closed: Issue closed
109 field_is_default: Default status
109 field_is_default: Default status
110 field_html_color: Color
110 field_html_color: Color
111 field_tracker: Tracker
111 field_tracker: Tracker
112 field_subject: Subject
112 field_subject: Subject
113 field_due_date: Due date
113 field_due_date: Due date
114 field_assigned_to: Assigned to
114 field_assigned_to: Assigned to
115 field_priority: Priority
115 field_priority: Priority
116 field_fixed_version: Fixed version
116 field_fixed_version: Fixed version
117 field_user: User
117 field_user: User
118 field_role: Role
118 field_role: Role
119 field_homepage: Homepage
119 field_homepage: Homepage
120 field_is_public: Public
120 field_is_public: Public
121 field_parent: Subproject of
121 field_parent: Subproject of
122 field_is_in_chlog: Issues displayed in changelog
122 field_is_in_chlog: Issues displayed in changelog
123 field_is_in_roadmap: Issues displayed in roadmap
123 field_is_in_roadmap: Issues displayed in roadmap
124 field_login: Login
124 field_login: Login
125 field_mail_notification: Mail notifications
125 field_mail_notification: Mail notifications
126 field_admin: Administrator
126 field_admin: Administrator
127 field_last_login_on: Last connection
127 field_last_login_on: Last connection
128 field_language: Language
128 field_language: Language
129 field_effective_date: Date
129 field_effective_date: Date
130 field_password: Password
130 field_password: Password
131 field_new_password: New password
131 field_new_password: New password
132 field_password_confirmation: Confirmation
132 field_password_confirmation: Confirmation
133 field_version: Version
133 field_version: Version
134 field_type: Type
134 field_type: Type
135 field_host: Host
135 field_host: Host
136 field_port: Port
136 field_port: Port
137 field_account: Account
137 field_account: Account
138 field_base_dn: Base DN
138 field_base_dn: Base DN
139 field_attr_login: Login attribute
139 field_attr_login: Login attribute
140 field_attr_firstname: Firstname attribute
140 field_attr_firstname: Firstname attribute
141 field_attr_lastname: Lastname attribute
141 field_attr_lastname: Lastname attribute
142 field_attr_mail: Email attribute
142 field_attr_mail: Email attribute
143 field_onthefly: On-the-fly user creation
143 field_onthefly: On-the-fly user creation
144 field_start_date: Start
144 field_start_date: Start
145 field_done_ratio: %% Done
145 field_done_ratio: %% Done
146 field_auth_source: Authentication mode
146 field_auth_source: Authentication mode
147 field_hide_mail: Hide my email address
147 field_hide_mail: Hide my email address
148 field_comments: Comment
148 field_comments: Comment
149 field_url: URL
149 field_url: URL
150 field_start_page: Start page
150 field_start_page: Start page
151 field_subproject: Subproject
151 field_subproject: Subproject
152 field_hours: Hours
152 field_hours: Hours
153 field_activity: Activity
153 field_activity: Activity
154 field_spent_on: Date
154 field_spent_on: Date
155 field_identifier: Identifier
155 field_identifier: Identifier
156 field_is_filter: Used as a filter
156 field_is_filter: Used as a filter
157 field_issue_to_id: Related issue
157 field_issue_to_id: Related issue
158 field_delay: Delay
158 field_delay: Delay
159 field_assignable: Issues can be assigned to this role
159 field_assignable: Issues can be assigned to this role
160 field_redirect_existing_links: Redirect existing links
160 field_redirect_existing_links: Redirect existing links
161 field_estimated_hours: Estimated time
161 field_estimated_hours: Estimated time
162
162
163 setting_app_title: Application title
163 setting_app_title: Application title
164 setting_app_subtitle: Application subtitle
164 setting_app_subtitle: Application subtitle
165 setting_welcome_text: Welcome text
165 setting_welcome_text: Welcome text
166 setting_default_language: Default language
166 setting_default_language: Default language
167 setting_login_required: Authent. required
167 setting_login_required: Authent. required
168 setting_self_registration: Self-registration enabled
168 setting_self_registration: Self-registration enabled
169 setting_attachment_max_size: Attachment max. size
169 setting_attachment_max_size: Attachment max. size
170 setting_issues_export_limit: Issues export limit
170 setting_issues_export_limit: Issues export limit
171 setting_mail_from: Emission mail address
171 setting_mail_from: Emission mail address
172 setting_host_name: Host name
172 setting_host_name: Host name
173 setting_text_formatting: Text formatting
173 setting_text_formatting: Text formatting
174 setting_wiki_compression: Wiki history compression
174 setting_wiki_compression: Wiki history compression
175 setting_feeds_limit: Feed content limit
175 setting_feeds_limit: Feed content limit
176 setting_autofetch_changesets: Autofetch commits
176 setting_autofetch_changesets: Autofetch commits
177 setting_sys_api_enabled: Enable WS for repository management
177 setting_sys_api_enabled: Enable WS for repository management
178 setting_commit_ref_keywords: Referencing keywords
178 setting_commit_ref_keywords: Referencing keywords
179 setting_commit_fix_keywords: Fixing keywords
179 setting_commit_fix_keywords: Fixing keywords
180 setting_autologin: Autologin
180 setting_autologin: Autologin
181 setting_date_format: Date format
181 setting_date_format: Date format
182 setting_cross_project_issue_relations: Allow cross-project issue relations
182 setting_cross_project_issue_relations: Allow cross-project issue relations
183
183
184 label_user: User
184 label_user: User
185 label_user_plural: Users
185 label_user_plural: Users
186 label_user_new: New user
186 label_user_new: New user
187 label_project: Project
187 label_project: Project
188 label_project_new: New project
188 label_project_new: New project
189 label_project_plural: Projects
189 label_project_plural: Projects
190 label_project_all: All Projects
190 label_project_all: All Projects
191 label_project_latest: Latest projects
191 label_project_latest: Latest projects
192 label_issue: Issue
192 label_issue: Issue
193 label_issue_new: New issue
193 label_issue_new: New issue
194 label_issue_plural: Issues
194 label_issue_plural: Issues
195 label_issue_view_all: View all issues
195 label_issue_view_all: View all issues
196 label_document: Document
196 label_document: Document
197 label_document_new: New document
197 label_document_new: New document
198 label_document_plural: Documents
198 label_document_plural: Documents
199 label_role: Role
199 label_role: Role
200 label_role_plural: Roles
200 label_role_plural: Roles
201 label_role_new: New role
201 label_role_new: New role
202 label_role_and_permissions: Roles and permissions
202 label_role_and_permissions: Roles and permissions
203 label_member: Member
203 label_member: Member
204 label_member_new: New member
204 label_member_new: New member
205 label_member_plural: Members
205 label_member_plural: Members
206 label_tracker: Tracker
206 label_tracker: Tracker
207 label_tracker_plural: Trackers
207 label_tracker_plural: Trackers
208 label_tracker_new: New tracker
208 label_tracker_new: New tracker
209 label_workflow: Workflow
209 label_workflow: Workflow
210 label_issue_status: Issue status
210 label_issue_status: Issue status
211 label_issue_status_plural: Issue statuses
211 label_issue_status_plural: Issue statuses
212 label_issue_status_new: New status
212 label_issue_status_new: New status
213 label_issue_category: Issue category
213 label_issue_category: Issue category
214 label_issue_category_plural: Issue categories
214 label_issue_category_plural: Issue categories
215 label_issue_category_new: New category
215 label_issue_category_new: New category
216 label_custom_field: Custom field
216 label_custom_field: Custom field
217 label_custom_field_plural: Custom fields
217 label_custom_field_plural: Custom fields
218 label_custom_field_new: New custom field
218 label_custom_field_new: New custom field
219 label_enumerations: Enumerations
219 label_enumerations: Enumerations
220 label_enumeration_new: New value
220 label_enumeration_new: New value
221 label_information: Information
221 label_information: Information
222 label_information_plural: Information
222 label_information_plural: Information
223 label_please_login: Please login
223 label_please_login: Please login
224 label_register: Register
224 label_register: Register
225 label_password_lost: Lost password
225 label_password_lost: Lost password
226 label_home: Home
226 label_home: Home
227 label_my_page: My page
227 label_my_page: My page
228 label_my_account: My account
228 label_my_account: My account
229 label_my_projects: My projects
229 label_my_projects: My projects
230 label_administration: Administration
230 label_administration: Administration
231 label_login: Sign in
231 label_login: Sign in
232 label_logout: Sign out
232 label_logout: Sign out
233 label_help: Help
233 label_help: Help
234 label_reported_issues: Reported issues
234 label_reported_issues: Reported issues
235 label_assigned_to_me_issues: Issues assigned to me
235 label_assigned_to_me_issues: Issues assigned to me
236 label_last_login: Last connection
236 label_last_login: Last connection
237 label_last_updates: Last updated
237 label_last_updates: Last updated
238 label_last_updates_plural: %d last updated
238 label_last_updates_plural: %d last updated
239 label_registered_on: Registered on
239 label_registered_on: Registered on
240 label_activity: Activity
240 label_activity: Activity
241 label_new: New
241 label_new: New
242 label_logged_as: Logged as
242 label_logged_as: Logged as
243 label_environment: Environment
243 label_environment: Environment
244 label_authentication: Authentication
244 label_authentication: Authentication
245 label_auth_source: Authentication mode
245 label_auth_source: Authentication mode
246 label_auth_source_new: New authentication mode
246 label_auth_source_new: New authentication mode
247 label_auth_source_plural: Authentication modes
247 label_auth_source_plural: Authentication modes
248 label_subproject_plural: Subprojects
248 label_subproject_plural: Subprojects
249 label_min_max_length: Min - Max length
249 label_min_max_length: Min - Max length
250 label_list: List
250 label_list: List
251 label_date: Date
251 label_date: Date
252 label_integer: Integer
252 label_integer: Integer
253 label_boolean: Boolean
253 label_boolean: Boolean
254 label_string: Text
254 label_string: Text
255 label_text: Long text
255 label_text: Long text
256 label_attribute: Attribute
256 label_attribute: Attribute
257 label_attribute_plural: Attributes
257 label_attribute_plural: Attributes
258 label_download: %d Download
258 label_download: %d Download
259 label_download_plural: %d Downloads
259 label_download_plural: %d Downloads
260 label_no_data: No data to display
260 label_no_data: No data to display
261 label_change_status: Change status
261 label_change_status: Change status
262 label_history: History
262 label_history: History
263 label_attachment: File
263 label_attachment: File
264 label_attachment_new: New file
264 label_attachment_new: New file
265 label_attachment_delete: Delete file
265 label_attachment_delete: Delete file
266 label_attachment_plural: Files
266 label_attachment_plural: Files
267 label_report: Report
267 label_report: Report
268 label_report_plural: Reports
268 label_report_plural: Reports
269 label_news: News
269 label_news: News
270 label_news_new: Add news
270 label_news_new: Add news
271 label_news_plural: News
271 label_news_plural: News
272 label_news_latest: Latest news
272 label_news_latest: Latest news
273 label_news_view_all: View all news
273 label_news_view_all: View all news
274 label_change_log: Change log
274 label_change_log: Change log
275 label_settings: Settings
275 label_settings: Settings
276 label_overview: Overview
276 label_overview: Overview
277 label_version: Version
277 label_version: Version
278 label_version_new: New version
278 label_version_new: New version
279 label_version_plural: Versions
279 label_version_plural: Versions
280 label_confirmation: Confirmation
280 label_confirmation: Confirmation
281 label_export_to: Export to
281 label_export_to: Export to
282 label_read: Read...
282 label_read: Read...
283 label_public_projects: Public projects
283 label_public_projects: Public projects
284 label_open_issues: open
284 label_open_issues: open
285 label_open_issues_plural: open
285 label_open_issues_plural: open
286 label_closed_issues: closed
286 label_closed_issues: closed
287 label_closed_issues_plural: closed
287 label_closed_issues_plural: closed
288 label_total: Total
288 label_total: Total
289 label_permissions: Permissions
289 label_permissions: Permissions
290 label_current_status: Current status
290 label_current_status: Current status
291 label_new_statuses_allowed: New statuses allowed
291 label_new_statuses_allowed: New statuses allowed
292 label_all: all
292 label_all: all
293 label_none: none
293 label_none: none
294 label_next: Next
294 label_next: Next
295 label_previous: Previous
295 label_previous: Previous
296 label_used_by: Used by
296 label_used_by: Used by
297 label_details: Details
297 label_details: Details
298 label_add_note: Add a note
298 label_add_note: Add a note
299 label_per_page: Per page
299 label_per_page: Per page
300 label_calendar: Calendar
300 label_calendar: Calendar
301 label_months_from: months from
301 label_months_from: months from
302 label_gantt: Gantt
302 label_gantt: Gantt
303 label_internal: Internal
303 label_internal: Internal
304 label_last_changes: last %d changes
304 label_last_changes: last %d changes
305 label_change_view_all: View all changes
305 label_change_view_all: View all changes
306 label_personalize_page: Personalize this page
306 label_personalize_page: Personalize this page
307 label_comment: Comment
307 label_comment: Comment
308 label_comment_plural: Comments
308 label_comment_plural: Comments
309 label_comment_add: Add a comment
309 label_comment_add: Add a comment
310 label_comment_added: Comment added
310 label_comment_added: Comment added
311 label_comment_delete: Delete comments
311 label_comment_delete: Delete comments
312 label_query: Custom query
312 label_query: Custom query
313 label_query_plural: Custom queries
313 label_query_plural: Custom queries
314 label_query_new: New query
314 label_query_new: New query
315 label_filter_add: Add filter
315 label_filter_add: Add filter
316 label_filter_plural: Filters
316 label_filter_plural: Filters
317 label_equals: is
317 label_equals: is
318 label_not_equals: is not
318 label_not_equals: is not
319 label_in_less_than: in less than
319 label_in_less_than: in less than
320 label_in_more_than: in more than
320 label_in_more_than: in more than
321 label_in: in
321 label_in: in
322 label_today: today
322 label_today: today
323 label_this_week: this week
323 label_this_week: this week
324 label_less_than_ago: less than days ago
324 label_less_than_ago: less than days ago
325 label_more_than_ago: more than days ago
325 label_more_than_ago: more than days ago
326 label_ago: days ago
326 label_ago: days ago
327 label_contains: contains
327 label_contains: contains
328 label_not_contains: doesn't contain
328 label_not_contains: doesn't contain
329 label_day_plural: days
329 label_day_plural: days
330 label_repository: Repository
330 label_repository: Repository
331 label_browse: Browse
331 label_browse: Browse
332 label_modification: %d change
332 label_modification: %d change
333 label_modification_plural: %d changes
333 label_modification_plural: %d changes
334 label_revision: Revision
334 label_revision: Revision
335 label_revision_plural: Revisions
335 label_revision_plural: Revisions
336 label_added: added
336 label_added: added
337 label_modified: modified
337 label_modified: modified
338 label_deleted: deleted
338 label_deleted: deleted
339 label_latest_revision: Latest revision
339 label_latest_revision: Latest revision
340 label_latest_revision_plural: Latest revisions
340 label_latest_revision_plural: Latest revisions
341 label_view_revisions: View revisions
341 label_view_revisions: View revisions
342 label_max_size: Maximum size
342 label_max_size: Maximum size
343 label_on: 'on'
343 label_on: 'on'
344 label_sort_highest: Move to top
344 label_sort_highest: Move to top
345 label_sort_higher: Move up
345 label_sort_higher: Move up
346 label_sort_lower: Move down
346 label_sort_lower: Move down
347 label_sort_lowest: Move to bottom
347 label_sort_lowest: Move to bottom
348 label_roadmap: Roadmap
348 label_roadmap: Roadmap
349 label_roadmap_due_in: Due in
349 label_roadmap_due_in: Due in
350 label_roadmap_overdue: %s late
350 label_roadmap_overdue: %s late
351 label_roadmap_no_issues: No issues for this version
351 label_roadmap_no_issues: No issues for this version
352 label_search: Search
352 label_search: Search
353 label_result: %d result
353 label_result_plural: Results
354 label_result_plural: %d results
355 label_all_words: All words
354 label_all_words: All words
356 label_wiki: Wiki
355 label_wiki: Wiki
357 label_wiki_edit: Wiki edit
356 label_wiki_edit: Wiki edit
358 label_wiki_edit_plural: Wiki edits
357 label_wiki_edit_plural: Wiki edits
359 label_wiki_page: Wiki page
358 label_wiki_page: Wiki page
360 label_wiki_page_plural: Wiki pages
359 label_wiki_page_plural: Wiki pages
361 label_page_index: Index
360 label_page_index: Index
362 label_current_version: Current version
361 label_current_version: Current version
363 label_preview: Preview
362 label_preview: Preview
364 label_feed_plural: Feeds
363 label_feed_plural: Feeds
365 label_changes_details: Details of all changes
364 label_changes_details: Details of all changes
366 label_issue_tracking: Issue tracking
365 label_issue_tracking: Issue tracking
367 label_spent_time: Spent time
366 label_spent_time: Spent time
368 label_f_hour: %.2f hour
367 label_f_hour: %.2f hour
369 label_f_hour_plural: %.2f hours
368 label_f_hour_plural: %.2f hours
370 label_time_tracking: Time tracking
369 label_time_tracking: Time tracking
371 label_change_plural: Changes
370 label_change_plural: Changes
372 label_statistics: Statistics
371 label_statistics: Statistics
373 label_commits_per_month: Commits per month
372 label_commits_per_month: Commits per month
374 label_commits_per_author: Commits per author
373 label_commits_per_author: Commits per author
375 label_view_diff: View differences
374 label_view_diff: View differences
376 label_diff_inline: inline
375 label_diff_inline: inline
377 label_diff_side_by_side: side by side
376 label_diff_side_by_side: side by side
378 label_options: Options
377 label_options: Options
379 label_copy_workflow_from: Copy workflow from
378 label_copy_workflow_from: Copy workflow from
380 label_permissions_report: Permissions report
379 label_permissions_report: Permissions report
381 label_watched_issues: Watched issues
380 label_watched_issues: Watched issues
382 label_related_issues: Related issues
381 label_related_issues: Related issues
383 label_applied_status: Applied status
382 label_applied_status: Applied status
384 label_loading: Loading...
383 label_loading: Loading...
385 label_relation_new: New relation
384 label_relation_new: New relation
386 label_relation_delete: Delete relation
385 label_relation_delete: Delete relation
387 label_relates_to: related to
386 label_relates_to: related to
388 label_duplicates: duplicates
387 label_duplicates: duplicates
389 label_blocks: blocks
388 label_blocks: blocks
390 label_blocked_by: blocked by
389 label_blocked_by: blocked by
391 label_precedes: precedes
390 label_precedes: precedes
392 label_follows: follows
391 label_follows: follows
393 label_end_to_start: end to start
392 label_end_to_start: end to start
394 label_end_to_end: end to end
393 label_end_to_end: end to end
395 label_start_to_start: start to start
394 label_start_to_start: start to start
396 label_start_to_end: start to end
395 label_start_to_end: start to end
397 label_stay_logged_in: Stay logged in
396 label_stay_logged_in: Stay logged in
398 label_disabled: disabled
397 label_disabled: disabled
399 label_show_completed_versions: Show completed versions
398 label_show_completed_versions: Show completed versions
400 label_me: me
399 label_me: me
401 label_board: Forum
400 label_board: Forum
402 label_board_new: New forum
401 label_board_new: New forum
403 label_board_plural: Forums
402 label_board_plural: Forums
404 label_topic_plural: Topics
403 label_topic_plural: Topics
405 label_message_plural: Messages
404 label_message_plural: Messages
406 label_message_last: Last message
405 label_message_last: Last message
407 label_message_new: New message
406 label_message_new: New message
408 label_reply_plural: Replies
407 label_reply_plural: Replies
409 label_send_information: Send account information to the user
408 label_send_information: Send account information to the user
410 label_year: Year
409 label_year: Year
411 label_month: Month
410 label_month: Month
412 label_week: Week
411 label_week: Week
413 label_date_from: From
412 label_date_from: From
414 label_date_to: To
413 label_date_to: To
415 label_language_based: Language based
414 label_language_based: Language based
416 label_sort_by: Sort by "%s"
415 label_sort_by: Sort by "%s"
417 label_send_test_email: Send a test email
416 label_send_test_email: Send a test email
418 label_feeds_access_key_created_on: RSS access key created %s ago
417 label_feeds_access_key_created_on: RSS access key created %s ago
419 label_module_plural: Modules
418 label_module_plural: Modules
420 label_added_time_by: Added by %s %s ago
419 label_added_time_by: Added by %s %s ago
421 label_updated_time: Updated %s ago
420 label_updated_time: Updated %s ago
422 label_jump_to_a_project: Jump to a project...
421 label_jump_to_a_project: Jump to a project...
423 label_file_plural: Files
422 label_file_plural: Files
424 label_changeset_plural: Changesets
423 label_changeset_plural: Changesets
425
424
426 button_login: Login
425 button_login: Login
427 button_submit: Submit
426 button_submit: Submit
428 button_save: Save
427 button_save: Save
429 button_check_all: Check all
428 button_check_all: Check all
430 button_uncheck_all: Uncheck all
429 button_uncheck_all: Uncheck all
431 button_delete: Delete
430 button_delete: Delete
432 button_create: Create
431 button_create: Create
433 button_test: Test
432 button_test: Test
434 button_edit: Edit
433 button_edit: Edit
435 button_add: Add
434 button_add: Add
436 button_change: Change
435 button_change: Change
437 button_apply: Apply
436 button_apply: Apply
438 button_clear: Clear
437 button_clear: Clear
439 button_lock: Lock
438 button_lock: Lock
440 button_unlock: Unlock
439 button_unlock: Unlock
441 button_download: Download
440 button_download: Download
442 button_list: List
441 button_list: List
443 button_view: View
442 button_view: View
444 button_move: Move
443 button_move: Move
445 button_back: Back
444 button_back: Back
446 button_cancel: Cancel
445 button_cancel: Cancel
447 button_activate: Activate
446 button_activate: Activate
448 button_sort: Sort
447 button_sort: Sort
449 button_log_time: Log time
448 button_log_time: Log time
450 button_rollback: Rollback to this version
449 button_rollback: Rollback to this version
451 button_watch: Watch
450 button_watch: Watch
452 button_unwatch: Unwatch
451 button_unwatch: Unwatch
453 button_reply: Reply
452 button_reply: Reply
454 button_archive: Archive
453 button_archive: Archive
455 button_unarchive: Unarchive
454 button_unarchive: Unarchive
456 button_reset: Reset
455 button_reset: Reset
457 button_rename: Rename
456 button_rename: Rename
458
457
459 status_active: active
458 status_active: active
460 status_registered: registered
459 status_registered: registered
461 status_locked: locked
460 status_locked: locked
462
461
463 text_select_mail_notifications: Select actions for which mail notifications should be sent.
462 text_select_mail_notifications: Select actions for which mail notifications should be sent.
464 text_regexp_info: eg. ^[A-Z0-9]+$
463 text_regexp_info: eg. ^[A-Z0-9]+$
465 text_min_max_length_info: 0 means no restriction
464 text_min_max_length_info: 0 means no restriction
466 text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ?
465 text_project_destroy_confirmation: Are you sure you want to delete this project and all related data ?
467 text_workflow_edit: Select a role and a tracker to edit the workflow
466 text_workflow_edit: Select a role and a tracker to edit the workflow
468 text_are_you_sure: Are you sure ?
467 text_are_you_sure: Are you sure ?
469 text_journal_changed: changed from %s to %s
468 text_journal_changed: changed from %s to %s
470 text_journal_set_to: set to %s
469 text_journal_set_to: set to %s
471 text_journal_deleted: deleted
470 text_journal_deleted: deleted
472 text_tip_task_begin_day: task beginning this day
471 text_tip_task_begin_day: task beginning this day
473 text_tip_task_end_day: task ending this day
472 text_tip_task_end_day: task ending this day
474 text_tip_task_begin_end_day: task beginning and ending this day
473 text_tip_task_begin_end_day: task beginning and ending this day
475 text_project_identifier_info: 'Lower case letters (a-z), numbers and dashes allowed.<br />Once saved, the identifier can not be changed.'
474 text_project_identifier_info: 'Lower case letters (a-z), numbers and dashes allowed.<br />Once saved, the identifier can not be changed.'
476 text_caracters_maximum: %d characters maximum.
475 text_caracters_maximum: %d characters maximum.
477 text_length_between: Length between %d and %d characters.
476 text_length_between: Length between %d and %d characters.
478 text_tracker_no_workflow: No workflow defined for this tracker
477 text_tracker_no_workflow: No workflow defined for this tracker
479 text_unallowed_characters: Unallowed characters
478 text_unallowed_characters: Unallowed characters
480 text_comma_separated: Multiple values allowed (comma separated).
479 text_comma_separated: Multiple values allowed (comma separated).
481 text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages
480 text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages
482 text_issue_added: Issue %s has been reported.
481 text_issue_added: Issue %s has been reported.
483 text_issue_updated: Issue %s has been updated.
482 text_issue_updated: Issue %s has been updated.
484 text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ?
483 text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ?
485 text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ?
484 text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ?
486 text_issue_category_destroy_assignments: Remove category assignments
485 text_issue_category_destroy_assignments: Remove category assignments
487 text_issue_category_reassign_to: Reassing issues to this category
486 text_issue_category_reassign_to: Reassing issues to this category
488
487
489 default_role_manager: Manager
488 default_role_manager: Manager
490 default_role_developper: Developer
489 default_role_developper: Developer
491 default_role_reporter: Reporter
490 default_role_reporter: Reporter
492 default_tracker_bug: Bug
491 default_tracker_bug: Bug
493 default_tracker_feature: Feature
492 default_tracker_feature: Feature
494 default_tracker_support: Support
493 default_tracker_support: Support
495 default_issue_status_new: New
494 default_issue_status_new: New
496 default_issue_status_assigned: Assigned
495 default_issue_status_assigned: Assigned
497 default_issue_status_resolved: Resolved
496 default_issue_status_resolved: Resolved
498 default_issue_status_feedback: Feedback
497 default_issue_status_feedback: Feedback
499 default_issue_status_closed: Closed
498 default_issue_status_closed: Closed
500 default_issue_status_rejected: Rejected
499 default_issue_status_rejected: Rejected
501 default_doc_category_user: User documentation
500 default_doc_category_user: User documentation
502 default_doc_category_tech: Technical documentation
501 default_doc_category_tech: Technical documentation
503 default_priority_low: Low
502 default_priority_low: Low
504 default_priority_normal: Normal
503 default_priority_normal: Normal
505 default_priority_high: High
504 default_priority_high: High
506 default_priority_urgent: Urgent
505 default_priority_urgent: Urgent
507 default_priority_immediate: Immediate
506 default_priority_immediate: Immediate
508 default_activity_design: Design
507 default_activity_design: Design
509 default_activity_development: Development
508 default_activity_development: Development
510
509
511 enumeration_issue_priorities: Issue priorities
510 enumeration_issue_priorities: Issue priorities
512 enumeration_doc_categories: Document categories
511 enumeration_doc_categories: Document categories
513 enumeration_activities: Activities (time tracking)
512 enumeration_activities: Activities (time tracking)
@@ -1,513 +1,512
1 _gloc_rule_default: '|n| n==1 ? "" : "_plural" '
1 _gloc_rule_default: '|n| n==1 ? "" : "_plural" '
2
2
3 actionview_datehelper_select_day_prefix:
3 actionview_datehelper_select_day_prefix:
4 actionview_datehelper_select_month_names: Janvier,FΓ©vrier,Mars,Avril,Mai,Juin,Juillet,AoΓ»t,Septembre,Octobre,Novembre,DΓ©cembre
4 actionview_datehelper_select_month_names: Janvier,FΓ©vrier,Mars,Avril,Mai,Juin,Juillet,AoΓ»t,Septembre,Octobre,Novembre,DΓ©cembre
5 actionview_datehelper_select_month_names_abbr: Jan,FΓ©v,Mars,Avril,Mai,Juin,Juil,AoΓ»t,Sept,Oct,Nov,DΓ©c
5 actionview_datehelper_select_month_names_abbr: Jan,FΓ©v,Mars,Avril,Mai,Juin,Juil,AoΓ»t,Sept,Oct,Nov,DΓ©c
6 actionview_datehelper_select_month_prefix:
6 actionview_datehelper_select_month_prefix:
7 actionview_datehelper_select_year_prefix:
7 actionview_datehelper_select_year_prefix:
8 actionview_datehelper_time_in_words_day: 1 jour
8 actionview_datehelper_time_in_words_day: 1 jour
9 actionview_datehelper_time_in_words_day_plural: %d jours
9 actionview_datehelper_time_in_words_day_plural: %d jours
10 actionview_datehelper_time_in_words_hour_about: environ une heure
10 actionview_datehelper_time_in_words_hour_about: environ une heure
11 actionview_datehelper_time_in_words_hour_about_plural: environ %d heures
11 actionview_datehelper_time_in_words_hour_about_plural: environ %d heures
12 actionview_datehelper_time_in_words_hour_about_single: environ une heure
12 actionview_datehelper_time_in_words_hour_about_single: environ une heure
13 actionview_datehelper_time_in_words_minute: 1 minute
13 actionview_datehelper_time_in_words_minute: 1 minute
14 actionview_datehelper_time_in_words_minute_half: 30 secondes
14 actionview_datehelper_time_in_words_minute_half: 30 secondes
15 actionview_datehelper_time_in_words_minute_less_than: moins d'une minute
15 actionview_datehelper_time_in_words_minute_less_than: moins d'une minute
16 actionview_datehelper_time_in_words_minute_plural: %d minutes
16 actionview_datehelper_time_in_words_minute_plural: %d minutes
17 actionview_datehelper_time_in_words_minute_single: 1 minute
17 actionview_datehelper_time_in_words_minute_single: 1 minute
18 actionview_datehelper_time_in_words_second_less_than: moins d'une seconde
18 actionview_datehelper_time_in_words_second_less_than: moins d'une seconde
19 actionview_datehelper_time_in_words_second_less_than_plural: moins de %d secondes
19 actionview_datehelper_time_in_words_second_less_than_plural: moins de %d secondes
20 actionview_instancetag_blank_option: Choisir
20 actionview_instancetag_blank_option: Choisir
21
21
22 activerecord_error_inclusion: n'est pas inclus dans la liste
22 activerecord_error_inclusion: n'est pas inclus dans la liste
23 activerecord_error_exclusion: est reservΓ©
23 activerecord_error_exclusion: est reservΓ©
24 activerecord_error_invalid: est invalide
24 activerecord_error_invalid: est invalide
25 activerecord_error_confirmation: ne correspond pas Γ  la confirmation
25 activerecord_error_confirmation: ne correspond pas Γ  la confirmation
26 activerecord_error_accepted: doit Γͺtre acceptΓ©
26 activerecord_error_accepted: doit Γͺtre acceptΓ©
27 activerecord_error_empty: doit Γͺtre renseignΓ©
27 activerecord_error_empty: doit Γͺtre renseignΓ©
28 activerecord_error_blank: doit Γͺtre renseignΓ©
28 activerecord_error_blank: doit Γͺtre renseignΓ©
29 activerecord_error_too_long: est trop long
29 activerecord_error_too_long: est trop long
30 activerecord_error_too_short: est trop court
30 activerecord_error_too_short: est trop court
31 activerecord_error_wrong_length: n'est pas de la bonne longueur
31 activerecord_error_wrong_length: n'est pas de la bonne longueur
32 activerecord_error_taken: est dΓ©jΓ  utilisΓ©
32 activerecord_error_taken: est dΓ©jΓ  utilisΓ©
33 activerecord_error_not_a_number: n'est pas un nombre
33 activerecord_error_not_a_number: n'est pas un nombre
34 activerecord_error_not_a_date: n'est pas une date valide
34 activerecord_error_not_a_date: n'est pas une date valide
35 activerecord_error_greater_than_start_date: doit Γͺtre postΓ©rieur Γ  la date de dΓ©but
35 activerecord_error_greater_than_start_date: doit Γͺtre postΓ©rieur Γ  la date de dΓ©but
36 activerecord_error_not_same_project: n'appartient pas au mΓͺme projet
36 activerecord_error_not_same_project: n'appartient pas au mΓͺme projet
37 activerecord_error_circular_dependency: Cette relation crΓ©erait une dΓ©pendance circulaire
37 activerecord_error_circular_dependency: Cette relation crΓ©erait une dΓ©pendance circulaire
38
38
39 general_fmt_age: %d an
39 general_fmt_age: %d an
40 general_fmt_age_plural: %d ans
40 general_fmt_age_plural: %d ans
41 general_fmt_date: %%d/%%m/%%Y
41 general_fmt_date: %%d/%%m/%%Y
42 general_fmt_datetime: %%d/%%m/%%Y %%H:%%M
42 general_fmt_datetime: %%d/%%m/%%Y %%H:%%M
43 general_fmt_datetime_short: %%d/%%m %%H:%%M
43 general_fmt_datetime_short: %%d/%%m %%H:%%M
44 general_fmt_time: %%H:%%M
44 general_fmt_time: %%H:%%M
45 general_text_No: 'Non'
45 general_text_No: 'Non'
46 general_text_Yes: 'Oui'
46 general_text_Yes: 'Oui'
47 general_text_no: 'non'
47 general_text_no: 'non'
48 general_text_yes: 'oui'
48 general_text_yes: 'oui'
49 general_lang_name: 'FranΓ§ais'
49 general_lang_name: 'FranΓ§ais'
50 general_csv_separator: ';'
50 general_csv_separator: ';'
51 general_csv_encoding: ISO-8859-1
51 general_csv_encoding: ISO-8859-1
52 general_pdf_encoding: ISO-8859-1
52 general_pdf_encoding: ISO-8859-1
53 general_day_names: Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche
53 general_day_names: Lundi,Mardi,Mercredi,Jeudi,Vendredi,Samedi,Dimanche
54
54
55 notice_account_updated: Le compte a été mis à jour avec succès.
55 notice_account_updated: Le compte a été mis à jour avec succès.
56 notice_account_invalid_creditentials: Identifiant ou mot de passe invalide.
56 notice_account_invalid_creditentials: Identifiant ou mot de passe invalide.
57 notice_account_password_updated: Mot de passe mis à jour avec succès.
57 notice_account_password_updated: Mot de passe mis à jour avec succès.
58 notice_account_wrong_password: Mot de passe incorrect
58 notice_account_wrong_password: Mot de passe incorrect
59 notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a Γ©tΓ© envoyΓ©.
59 notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a Γ©tΓ© envoyΓ©.
60 notice_account_unknown_email: Aucun compte ne correspond Γ  cette adresse.
60 notice_account_unknown_email: Aucun compte ne correspond Γ  cette adresse.
61 notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe.
61 notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe.
62 notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a Γ©tΓ© envoyΓ©.
62 notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a Γ©tΓ© envoyΓ©.
63 notice_account_activated: Votre compte a Γ©tΓ© activΓ©. Vous pouvez Γ  prΓ©sent vous connecter.
63 notice_account_activated: Votre compte a Γ©tΓ© activΓ©. Vous pouvez Γ  prΓ©sent vous connecter.
64 notice_successful_create: Création effectuée avec succès.
64 notice_successful_create: Création effectuée avec succès.
65 notice_successful_update: Mise à jour effectuée avec succès.
65 notice_successful_update: Mise à jour effectuée avec succès.
66 notice_successful_delete: Suppression effectuée avec succès.
66 notice_successful_delete: Suppression effectuée avec succès.
67 notice_successful_connection: Connection rΓ©ussie.
67 notice_successful_connection: Connection rΓ©ussie.
68 notice_file_not_found: "La page Γ  laquelle vous souhaitez accΓ©der n'existe pas ou a Γ©tΓ© supprimΓ©e."
68 notice_file_not_found: "La page Γ  laquelle vous souhaitez accΓ©der n'existe pas ou a Γ©tΓ© supprimΓ©e."
69 notice_locking_conflict: Les donnΓ©es ont Γ©tΓ© mises Γ  jour par un autre utilisateur. Mise Γ  jour impossible.
69 notice_locking_conflict: Les donnΓ©es ont Γ©tΓ© mises Γ  jour par un autre utilisateur. Mise Γ  jour impossible.
70 notice_scm_error: "L'entrΓ©e et/ou la rΓ©vision demandΓ©e n'existe pas dans le dΓ©pΓ΄t."
70 notice_scm_error: "L'entrΓ©e et/ou la rΓ©vision demandΓ©e n'existe pas dans le dΓ©pΓ΄t."
71 notice_not_authorized: "Vous n'Γͺtes pas autorisΓ©s Γ  accΓ©der Γ  cette page."
71 notice_not_authorized: "Vous n'Γͺtes pas autorisΓ©s Γ  accΓ©der Γ  cette page."
72 notice_email_sent: "Un email a Γ©tΓ© envoyΓ© Γ  %s"
72 notice_email_sent: "Un email a Γ©tΓ© envoyΓ© Γ  %s"
73 notice_email_error: "Erreur lors de l'envoi de l'email (%s)"
73 notice_email_error: "Erreur lors de l'envoi de l'email (%s)"
74 notice_feeds_access_key_reseted: Votre clé d'accès aux flux RSS a été réinitialisée.
74 notice_feeds_access_key_reseted: Votre clé d'accès aux flux RSS a été réinitialisée.
75
75
76 mail_subject_lost_password: Votre mot de passe redMine
76 mail_subject_lost_password: Votre mot de passe redMine
77 mail_subject_register: Activation de votre compte redMine
77 mail_subject_register: Activation de votre compte redMine
78
78
79 gui_validation_error: 1 erreur
79 gui_validation_error: 1 erreur
80 gui_validation_error_plural: %d erreurs
80 gui_validation_error_plural: %d erreurs
81
81
82 field_name: Nom
82 field_name: Nom
83 field_description: Description
83 field_description: Description
84 field_summary: RΓ©sumΓ©
84 field_summary: RΓ©sumΓ©
85 field_is_required: Obligatoire
85 field_is_required: Obligatoire
86 field_firstname: PrΓ©nom
86 field_firstname: PrΓ©nom
87 field_lastname: Nom
87 field_lastname: Nom
88 field_mail: Email
88 field_mail: Email
89 field_filename: Fichier
89 field_filename: Fichier
90 field_filesize: Taille
90 field_filesize: Taille
91 field_downloads: TΓ©lΓ©chargements
91 field_downloads: TΓ©lΓ©chargements
92 field_author: Auteur
92 field_author: Auteur
93 field_created_on: Créé
93 field_created_on: Créé
94 field_updated_on: Mis Γ  jour
94 field_updated_on: Mis Γ  jour
95 field_field_format: Format
95 field_field_format: Format
96 field_is_for_all: Pour tous les projets
96 field_is_for_all: Pour tous les projets
97 field_possible_values: Valeurs possibles
97 field_possible_values: Valeurs possibles
98 field_regexp: Expression régulière
98 field_regexp: Expression régulière
99 field_min_length: Longueur minimum
99 field_min_length: Longueur minimum
100 field_max_length: Longueur maximum
100 field_max_length: Longueur maximum
101 field_value: Valeur
101 field_value: Valeur
102 field_category: CatΓ©gorie
102 field_category: CatΓ©gorie
103 field_title: Titre
103 field_title: Titre
104 field_project: Projet
104 field_project: Projet
105 field_issue: Demande
105 field_issue: Demande
106 field_status: Statut
106 field_status: Statut
107 field_notes: Notes
107 field_notes: Notes
108 field_is_closed: Demande fermΓ©e
108 field_is_closed: Demande fermΓ©e
109 field_is_default: Statut par dΓ©faut
109 field_is_default: Statut par dΓ©faut
110 field_html_color: Couleur
110 field_html_color: Couleur
111 field_tracker: Tracker
111 field_tracker: Tracker
112 field_subject: Sujet
112 field_subject: Sujet
113 field_due_date: Date d'Γ©chΓ©ance
113 field_due_date: Date d'Γ©chΓ©ance
114 field_assigned_to: AssignΓ© Γ 
114 field_assigned_to: AssignΓ© Γ 
115 field_priority: PrioritΓ©
115 field_priority: PrioritΓ©
116 field_fixed_version: Version corrigΓ©e
116 field_fixed_version: Version corrigΓ©e
117 field_user: Utilisateur
117 field_user: Utilisateur
118 field_role: RΓ΄le
118 field_role: RΓ΄le
119 field_homepage: Site web
119 field_homepage: Site web
120 field_is_public: Public
120 field_is_public: Public
121 field_parent: Sous-projet de
121 field_parent: Sous-projet de
122 field_is_in_chlog: Demandes affichΓ©es dans l'historique
122 field_is_in_chlog: Demandes affichΓ©es dans l'historique
123 field_is_in_roadmap: Demandes affichΓ©es dans la roadmap
123 field_is_in_roadmap: Demandes affichΓ©es dans la roadmap
124 field_login: Identifiant
124 field_login: Identifiant
125 field_mail_notification: Notifications par mail
125 field_mail_notification: Notifications par mail
126 field_admin: Administrateur
126 field_admin: Administrateur
127 field_last_login_on: Dernière connexion
127 field_last_login_on: Dernière connexion
128 field_language: Langue
128 field_language: Langue
129 field_effective_date: Date
129 field_effective_date: Date
130 field_password: Mot de passe
130 field_password: Mot de passe
131 field_new_password: Nouveau mot de passe
131 field_new_password: Nouveau mot de passe
132 field_password_confirmation: Confirmation
132 field_password_confirmation: Confirmation
133 field_version: Version
133 field_version: Version
134 field_type: Type
134 field_type: Type
135 field_host: HΓ΄te
135 field_host: HΓ΄te
136 field_port: Port
136 field_port: Port
137 field_account: Compte
137 field_account: Compte
138 field_base_dn: Base DN
138 field_base_dn: Base DN
139 field_attr_login: Attribut Identifiant
139 field_attr_login: Attribut Identifiant
140 field_attr_firstname: Attribut PrΓ©nom
140 field_attr_firstname: Attribut PrΓ©nom
141 field_attr_lastname: Attribut Nom
141 field_attr_lastname: Attribut Nom
142 field_attr_mail: Attribut Email
142 field_attr_mail: Attribut Email
143 field_onthefly: CrΓ©ation des utilisateurs Γ  la volΓ©e
143 field_onthefly: CrΓ©ation des utilisateurs Γ  la volΓ©e
144 field_start_date: DΓ©but
144 field_start_date: DΓ©but
145 field_done_ratio: %% RΓ©alisΓ©
145 field_done_ratio: %% RΓ©alisΓ©
146 field_auth_source: Mode d'authentification
146 field_auth_source: Mode d'authentification
147 field_hide_mail: Cacher mon adresse mail
147 field_hide_mail: Cacher mon adresse mail
148 field_comments: Commentaire
148 field_comments: Commentaire
149 field_url: URL
149 field_url: URL
150 field_start_page: Page de dΓ©marrage
150 field_start_page: Page de dΓ©marrage
151 field_subproject: Sous-projet
151 field_subproject: Sous-projet
152 field_hours: Heures
152 field_hours: Heures
153 field_activity: ActivitΓ©
153 field_activity: ActivitΓ©
154 field_spent_on: Date
154 field_spent_on: Date
155 field_identifier: Identifiant
155 field_identifier: Identifiant
156 field_is_filter: UtilisΓ© comme filtre
156 field_is_filter: UtilisΓ© comme filtre
157 field_issue_to_id: Demande liΓ©e
157 field_issue_to_id: Demande liΓ©e
158 field_delay: Retard
158 field_delay: Retard
159 field_assignable: Demandes assignables Γ  ce rΓ΄le
159 field_assignable: Demandes assignables Γ  ce rΓ΄le
160 field_redirect_existing_links: Rediriger les liens existants
160 field_redirect_existing_links: Rediriger les liens existants
161 field_estimated_hours: Temps estimΓ©
161 field_estimated_hours: Temps estimΓ©
162
162
163 setting_app_title: Titre de l'application
163 setting_app_title: Titre de l'application
164 setting_app_subtitle: Sous-titre de l'application
164 setting_app_subtitle: Sous-titre de l'application
165 setting_welcome_text: Texte d'accueil
165 setting_welcome_text: Texte d'accueil
166 setting_default_language: Langue par dΓ©faut
166 setting_default_language: Langue par dΓ©faut
167 setting_login_required: Authentif. obligatoire
167 setting_login_required: Authentif. obligatoire
168 setting_self_registration: Enregistrement autorisΓ©
168 setting_self_registration: Enregistrement autorisΓ©
169 setting_attachment_max_size: Taille max des fichiers
169 setting_attachment_max_size: Taille max des fichiers
170 setting_issues_export_limit: Limite export demandes
170 setting_issues_export_limit: Limite export demandes
171 setting_mail_from: Adresse d'Γ©mission
171 setting_mail_from: Adresse d'Γ©mission
172 setting_host_name: Nom d'hΓ΄te
172 setting_host_name: Nom d'hΓ΄te
173 setting_text_formatting: Formatage du texte
173 setting_text_formatting: Formatage du texte
174 setting_wiki_compression: Compression historique wiki
174 setting_wiki_compression: Compression historique wiki
175 setting_feeds_limit: Limite du contenu des flux RSS
175 setting_feeds_limit: Limite du contenu des flux RSS
176 setting_autofetch_changesets: RΓ©cupΓ©ration auto. des commits
176 setting_autofetch_changesets: RΓ©cupΓ©ration auto. des commits
177 setting_sys_api_enabled: Activer les WS pour la gestion des dΓ©pΓ΄ts
177 setting_sys_api_enabled: Activer les WS pour la gestion des dΓ©pΓ΄ts
178 setting_commit_ref_keywords: Mot-clΓ©s de rΓ©fΓ©rencement
178 setting_commit_ref_keywords: Mot-clΓ©s de rΓ©fΓ©rencement
179 setting_commit_fix_keywords: Mot-clΓ©s de rΓ©solution
179 setting_commit_fix_keywords: Mot-clΓ©s de rΓ©solution
180 setting_autologin: Autologin
180 setting_autologin: Autologin
181 setting_date_format: Format de date
181 setting_date_format: Format de date
182 setting_cross_project_issue_relations: Autoriser les relations entre demandes de diffΓ©rents projets
182 setting_cross_project_issue_relations: Autoriser les relations entre demandes de diffΓ©rents projets
183
183
184 label_user: Utilisateur
184 label_user: Utilisateur
185 label_user_plural: Utilisateurs
185 label_user_plural: Utilisateurs
186 label_user_new: Nouvel utilisateur
186 label_user_new: Nouvel utilisateur
187 label_project: Projet
187 label_project: Projet
188 label_project_new: Nouveau projet
188 label_project_new: Nouveau projet
189 label_project_plural: Projets
189 label_project_plural: Projets
190 label_project_all: Tous les projets
190 label_project_all: Tous les projets
191 label_project_latest: Derniers projets
191 label_project_latest: Derniers projets
192 label_issue: Demande
192 label_issue: Demande
193 label_issue_new: Nouvelle demande
193 label_issue_new: Nouvelle demande
194 label_issue_plural: Demandes
194 label_issue_plural: Demandes
195 label_issue_view_all: Voir toutes les demandes
195 label_issue_view_all: Voir toutes les demandes
196 label_document: Document
196 label_document: Document
197 label_document_new: Nouveau document
197 label_document_new: Nouveau document
198 label_document_plural: Documents
198 label_document_plural: Documents
199 label_role: RΓ΄le
199 label_role: RΓ΄le
200 label_role_plural: RΓ΄les
200 label_role_plural: RΓ΄les
201 label_role_new: Nouveau rΓ΄le
201 label_role_new: Nouveau rΓ΄le
202 label_role_and_permissions: RΓ΄les et permissions
202 label_role_and_permissions: RΓ΄les et permissions
203 label_member: Membre
203 label_member: Membre
204 label_member_new: Nouveau membre
204 label_member_new: Nouveau membre
205 label_member_plural: Membres
205 label_member_plural: Membres
206 label_tracker: Tracker
206 label_tracker: Tracker
207 label_tracker_plural: Trackers
207 label_tracker_plural: Trackers
208 label_tracker_new: Nouveau tracker
208 label_tracker_new: Nouveau tracker
209 label_workflow: Workflow
209 label_workflow: Workflow
210 label_issue_status: Statut de demandes
210 label_issue_status: Statut de demandes
211 label_issue_status_plural: Statuts de demandes
211 label_issue_status_plural: Statuts de demandes
212 label_issue_status_new: Nouveau statut
212 label_issue_status_new: Nouveau statut
213 label_issue_category: CatΓ©gorie de demandes
213 label_issue_category: CatΓ©gorie de demandes
214 label_issue_category_plural: CatΓ©gories de demandes
214 label_issue_category_plural: CatΓ©gories de demandes
215 label_issue_category_new: Nouvelle catΓ©gorie
215 label_issue_category_new: Nouvelle catΓ©gorie
216 label_custom_field: Champ personnalisΓ©
216 label_custom_field: Champ personnalisΓ©
217 label_custom_field_plural: Champs personnalisΓ©s
217 label_custom_field_plural: Champs personnalisΓ©s
218 label_custom_field_new: Nouveau champ personnalisΓ©
218 label_custom_field_new: Nouveau champ personnalisΓ©
219 label_enumerations: Listes de valeurs
219 label_enumerations: Listes de valeurs
220 label_enumeration_new: Nouvelle valeur
220 label_enumeration_new: Nouvelle valeur
221 label_information: Information
221 label_information: Information
222 label_information_plural: Informations
222 label_information_plural: Informations
223 label_please_login: Identification
223 label_please_login: Identification
224 label_register: S'enregistrer
224 label_register: S'enregistrer
225 label_password_lost: Mot de passe perdu
225 label_password_lost: Mot de passe perdu
226 label_home: Accueil
226 label_home: Accueil
227 label_my_page: Ma page
227 label_my_page: Ma page
228 label_my_account: Mon compte
228 label_my_account: Mon compte
229 label_my_projects: Mes projets
229 label_my_projects: Mes projets
230 label_administration: Administration
230 label_administration: Administration
231 label_login: Connexion
231 label_login: Connexion
232 label_logout: DΓ©connexion
232 label_logout: DΓ©connexion
233 label_help: Aide
233 label_help: Aide
234 label_reported_issues: Demandes soumises
234 label_reported_issues: Demandes soumises
235 label_assigned_to_me_issues: Demandes qui me sont assignΓ©es
235 label_assigned_to_me_issues: Demandes qui me sont assignΓ©es
236 label_last_login: Dernière connexion
236 label_last_login: Dernière connexion
237 label_last_updates: Dernière mise à jour
237 label_last_updates: Dernière mise à jour
238 label_last_updates_plural: %d dernières mises à jour
238 label_last_updates_plural: %d dernières mises à jour
239 label_registered_on: Inscrit le
239 label_registered_on: Inscrit le
240 label_activity: ActivitΓ©
240 label_activity: ActivitΓ©
241 label_new: Nouveau
241 label_new: Nouveau
242 label_logged_as: ConnectΓ© en tant que
242 label_logged_as: ConnectΓ© en tant que
243 label_environment: Environnement
243 label_environment: Environnement
244 label_authentication: Authentification
244 label_authentication: Authentification
245 label_auth_source: Mode d'authentification
245 label_auth_source: Mode d'authentification
246 label_auth_source_new: Nouveau mode d'authentification
246 label_auth_source_new: Nouveau mode d'authentification
247 label_auth_source_plural: Modes d'authentification
247 label_auth_source_plural: Modes d'authentification
248 label_subproject_plural: Sous-projets
248 label_subproject_plural: Sous-projets
249 label_min_max_length: Longueurs mini - maxi
249 label_min_max_length: Longueurs mini - maxi
250 label_list: Liste
250 label_list: Liste
251 label_date: Date
251 label_date: Date
252 label_integer: Entier
252 label_integer: Entier
253 label_boolean: BoolΓ©en
253 label_boolean: BoolΓ©en
254 label_string: Texte
254 label_string: Texte
255 label_text: Texte long
255 label_text: Texte long
256 label_attribute: Attribut
256 label_attribute: Attribut
257 label_attribute_plural: Attributs
257 label_attribute_plural: Attributs
258 label_download: %d TΓ©lΓ©chargement
258 label_download: %d TΓ©lΓ©chargement
259 label_download_plural: %d TΓ©lΓ©chargements
259 label_download_plural: %d TΓ©lΓ©chargements
260 label_no_data: Aucune donnΓ©e Γ  afficher
260 label_no_data: Aucune donnΓ©e Γ  afficher
261 label_change_status: Changer le statut
261 label_change_status: Changer le statut
262 label_history: Historique
262 label_history: Historique
263 label_attachment: Fichier
263 label_attachment: Fichier
264 label_attachment_new: Nouveau fichier
264 label_attachment_new: Nouveau fichier
265 label_attachment_delete: Supprimer le fichier
265 label_attachment_delete: Supprimer le fichier
266 label_attachment_plural: Fichiers
266 label_attachment_plural: Fichiers
267 label_report: Rapport
267 label_report: Rapport
268 label_report_plural: Rapports
268 label_report_plural: Rapports
269 label_news: Annonce
269 label_news: Annonce
270 label_news_new: Nouvelle annonce
270 label_news_new: Nouvelle annonce
271 label_news_plural: Annonces
271 label_news_plural: Annonces
272 label_news_latest: Dernières annonces
272 label_news_latest: Dernières annonces
273 label_news_view_all: Voir toutes les annonces
273 label_news_view_all: Voir toutes les annonces
274 label_change_log: Historique
274 label_change_log: Historique
275 label_settings: Configuration
275 label_settings: Configuration
276 label_overview: AperΓ§u
276 label_overview: AperΓ§u
277 label_version: Version
277 label_version: Version
278 label_version_new: Nouvelle version
278 label_version_new: Nouvelle version
279 label_version_plural: Versions
279 label_version_plural: Versions
280 label_confirmation: Confirmation
280 label_confirmation: Confirmation
281 label_export_to: Exporter en
281 label_export_to: Exporter en
282 label_read: Lire...
282 label_read: Lire...
283 label_public_projects: Projets publics
283 label_public_projects: Projets publics
284 label_open_issues: ouvert
284 label_open_issues: ouvert
285 label_open_issues_plural: ouverts
285 label_open_issues_plural: ouverts
286 label_closed_issues: fermΓ©
286 label_closed_issues: fermΓ©
287 label_closed_issues_plural: fermΓ©s
287 label_closed_issues_plural: fermΓ©s
288 label_total: Total
288 label_total: Total
289 label_permissions: Permissions
289 label_permissions: Permissions
290 label_current_status: Statut actuel
290 label_current_status: Statut actuel
291 label_new_statuses_allowed: Nouveaux statuts autorisΓ©s
291 label_new_statuses_allowed: Nouveaux statuts autorisΓ©s
292 label_all: tous
292 label_all: tous
293 label_none: aucun
293 label_none: aucun
294 label_next: Suivant
294 label_next: Suivant
295 label_previous: PrΓ©cΓ©dent
295 label_previous: PrΓ©cΓ©dent
296 label_used_by: UtilisΓ© par
296 label_used_by: UtilisΓ© par
297 label_details: DΓ©tails
297 label_details: DΓ©tails
298 label_add_note: Ajouter une note
298 label_add_note: Ajouter une note
299 label_per_page: Par page
299 label_per_page: Par page
300 label_calendar: Calendrier
300 label_calendar: Calendrier
301 label_months_from: mois depuis
301 label_months_from: mois depuis
302 label_gantt: Gantt
302 label_gantt: Gantt
303 label_internal: Interne
303 label_internal: Interne
304 label_last_changes: %d derniers changements
304 label_last_changes: %d derniers changements
305 label_change_view_all: Voir tous les changements
305 label_change_view_all: Voir tous les changements
306 label_personalize_page: Personnaliser cette page
306 label_personalize_page: Personnaliser cette page
307 label_comment: Commentaire
307 label_comment: Commentaire
308 label_comment_plural: Commentaires
308 label_comment_plural: Commentaires
309 label_comment_add: Ajouter un commentaire
309 label_comment_add: Ajouter un commentaire
310 label_comment_added: Commentaire ajoutΓ©
310 label_comment_added: Commentaire ajoutΓ©
311 label_comment_delete: Supprimer les commentaires
311 label_comment_delete: Supprimer les commentaires
312 label_query: Rapport personnalisΓ©
312 label_query: Rapport personnalisΓ©
313 label_query_plural: Rapports personnalisΓ©s
313 label_query_plural: Rapports personnalisΓ©s
314 label_query_new: Nouveau rapport
314 label_query_new: Nouveau rapport
315 label_filter_add: Ajouter le filtre
315 label_filter_add: Ajouter le filtre
316 label_filter_plural: Filtres
316 label_filter_plural: Filtres
317 label_equals: Γ©gal
317 label_equals: Γ©gal
318 label_not_equals: diffΓ©rent
318 label_not_equals: diffΓ©rent
319 label_in_less_than: dans moins de
319 label_in_less_than: dans moins de
320 label_in_more_than: dans plus de
320 label_in_more_than: dans plus de
321 label_in: dans
321 label_in: dans
322 label_today: aujourd'hui
322 label_today: aujourd'hui
323 label_this_week: cette semaine
323 label_this_week: cette semaine
324 label_less_than_ago: il y a moins de
324 label_less_than_ago: il y a moins de
325 label_more_than_ago: il y a plus de
325 label_more_than_ago: il y a plus de
326 label_ago: il y a
326 label_ago: il y a
327 label_contains: contient
327 label_contains: contient
328 label_not_contains: ne contient pas
328 label_not_contains: ne contient pas
329 label_day_plural: jours
329 label_day_plural: jours
330 label_repository: DΓ©pΓ΄t
330 label_repository: DΓ©pΓ΄t
331 label_browse: Parcourir
331 label_browse: Parcourir
332 label_modification: %d modification
332 label_modification: %d modification
333 label_modification_plural: %d modifications
333 label_modification_plural: %d modifications
334 label_revision: RΓ©vision
334 label_revision: RΓ©vision
335 label_revision_plural: RΓ©visions
335 label_revision_plural: RΓ©visions
336 label_added: ajoutΓ©
336 label_added: ajoutΓ©
337 label_modified: modifiΓ©
337 label_modified: modifiΓ©
338 label_deleted: supprimΓ©
338 label_deleted: supprimΓ©
339 label_latest_revision: Dernière révision
339 label_latest_revision: Dernière révision
340 label_latest_revision_plural: Dernières révisions
340 label_latest_revision_plural: Dernières révisions
341 label_view_revisions: Voir les rΓ©visions
341 label_view_revisions: Voir les rΓ©visions
342 label_max_size: Taille maximale
342 label_max_size: Taille maximale
343 label_on: sur
343 label_on: sur
344 label_sort_highest: Remonter en premier
344 label_sort_highest: Remonter en premier
345 label_sort_higher: Remonter
345 label_sort_higher: Remonter
346 label_sort_lower: Descendre
346 label_sort_lower: Descendre
347 label_sort_lowest: Descendre en dernier
347 label_sort_lowest: Descendre en dernier
348 label_roadmap: Roadmap
348 label_roadmap: Roadmap
349 label_roadmap_due_in: EchΓ©ance dans
349 label_roadmap_due_in: EchΓ©ance dans
350 label_roadmap_overdue: En retard de %s
350 label_roadmap_overdue: En retard de %s
351 label_roadmap_no_issues: Aucune demande pour cette version
351 label_roadmap_no_issues: Aucune demande pour cette version
352 label_search: Recherche
352 label_search: Recherche
353 label_result: %d rΓ©sultat
353 label_result_plural: RΓ©sultats
354 label_result_plural: %d rΓ©sultats
355 label_all_words: Tous les mots
354 label_all_words: Tous les mots
356 label_wiki: Wiki
355 label_wiki: Wiki
357 label_wiki_edit: RΓ©vision wiki
356 label_wiki_edit: RΓ©vision wiki
358 label_wiki_edit_plural: RΓ©visions wiki
357 label_wiki_edit_plural: RΓ©visions wiki
359 label_wiki_page: Page wiki
358 label_wiki_page: Page wiki
360 label_wiki_page_plural: Pages wiki
359 label_wiki_page_plural: Pages wiki
361 label_page_index: Index
360 label_page_index: Index
362 label_current_version: Version actuelle
361 label_current_version: Version actuelle
363 label_preview: PrΓ©visualisation
362 label_preview: PrΓ©visualisation
364 label_feed_plural: Flux RSS
363 label_feed_plural: Flux RSS
365 label_changes_details: DΓ©tails de tous les changements
364 label_changes_details: DΓ©tails de tous les changements
366 label_issue_tracking: Suivi des demandes
365 label_issue_tracking: Suivi des demandes
367 label_spent_time: Temps passΓ©
366 label_spent_time: Temps passΓ©
368 label_f_hour: %.2f heure
367 label_f_hour: %.2f heure
369 label_f_hour_plural: %.2f heures
368 label_f_hour_plural: %.2f heures
370 label_time_tracking: Suivi du temps
369 label_time_tracking: Suivi du temps
371 label_change_plural: Changements
370 label_change_plural: Changements
372 label_statistics: Statistiques
371 label_statistics: Statistiques
373 label_commits_per_month: Commits par mois
372 label_commits_per_month: Commits par mois
374 label_commits_per_author: Commits par auteur
373 label_commits_per_author: Commits par auteur
375 label_view_diff: Voir les diffΓ©rences
374 label_view_diff: Voir les diffΓ©rences
376 label_diff_inline: en ligne
375 label_diff_inline: en ligne
377 label_diff_side_by_side: cΓ΄te Γ  cΓ΄te
376 label_diff_side_by_side: cΓ΄te Γ  cΓ΄te
378 label_options: Options
377 label_options: Options
379 label_copy_workflow_from: Copier le workflow de
378 label_copy_workflow_from: Copier le workflow de
380 label_permissions_report: Synthèse des permissions
379 label_permissions_report: Synthèse des permissions
381 label_watched_issues: Demandes surveillΓ©es
380 label_watched_issues: Demandes surveillΓ©es
382 label_related_issues: Demandes liΓ©es
381 label_related_issues: Demandes liΓ©es
383 label_applied_status: Statut appliquΓ©
382 label_applied_status: Statut appliquΓ©
384 label_loading: Chargement...
383 label_loading: Chargement...
385 label_relation_new: Nouvelle relation
384 label_relation_new: Nouvelle relation
386 label_relation_delete: Supprimer la relation
385 label_relation_delete: Supprimer la relation
387 label_relates_to: liΓ© Γ 
386 label_relates_to: liΓ© Γ 
388 label_duplicates: doublon de
387 label_duplicates: doublon de
389 label_blocks: bloque
388 label_blocks: bloque
390 label_blocked_by: bloquΓ© par
389 label_blocked_by: bloquΓ© par
391 label_precedes: précède
390 label_precedes: précède
392 label_follows: suit
391 label_follows: suit
393 label_end_to_start: fin Γ  dΓ©but
392 label_end_to_start: fin Γ  dΓ©but
394 label_end_to_end: fin Γ  fin
393 label_end_to_end: fin Γ  fin
395 label_start_to_start: dΓ©but Γ  dΓ©but
394 label_start_to_start: dΓ©but Γ  dΓ©but
396 label_start_to_end: dΓ©but Γ  fin
395 label_start_to_end: dΓ©but Γ  fin
397 label_stay_logged_in: Rester connectΓ©
396 label_stay_logged_in: Rester connectΓ©
398 label_disabled: dΓ©sactivΓ©
397 label_disabled: dΓ©sactivΓ©
399 label_show_completed_versions: Voire les versions passΓ©es
398 label_show_completed_versions: Voire les versions passΓ©es
400 label_me: moi
399 label_me: moi
401 label_board: Forum
400 label_board: Forum
402 label_board_new: Nouveau forum
401 label_board_new: Nouveau forum
403 label_board_plural: Forums
402 label_board_plural: Forums
404 label_topic_plural: Discussions
403 label_topic_plural: Discussions
405 label_message_plural: Messages
404 label_message_plural: Messages
406 label_message_last: Dernier message
405 label_message_last: Dernier message
407 label_message_new: Nouveau message
406 label_message_new: Nouveau message
408 label_reply_plural: RΓ©ponses
407 label_reply_plural: RΓ©ponses
409 label_send_information: Envoyer les informations Γ  l'utilisateur
408 label_send_information: Envoyer les informations Γ  l'utilisateur
410 label_year: AnnΓ©e
409 label_year: AnnΓ©e
411 label_month: Mois
410 label_month: Mois
412 label_week: Semaine
411 label_week: Semaine
413 label_date_from: Du
412 label_date_from: Du
414 label_date_to: Au
413 label_date_to: Au
415 label_language_based: BasΓ© sur la langue
414 label_language_based: BasΓ© sur la langue
416 label_sort_by: Trier par "%s"
415 label_sort_by: Trier par "%s"
417 label_send_test_email: Envoyer un email de test
416 label_send_test_email: Envoyer un email de test
418 label_feeds_access_key_created_on: Clé d'accès RSS créée il y a %s
417 label_feeds_access_key_created_on: Clé d'accès RSS créée il y a %s
419 label_module_plural: Modules
418 label_module_plural: Modules
420 label_added_time_by: AjoutΓ© par %s il y a %s
419 label_added_time_by: AjoutΓ© par %s il y a %s
421 label_updated_time: Mis Γ  jour il y a %s
420 label_updated_time: Mis Γ  jour il y a %s
422 label_jump_to_a_project: Aller Γ  un projet...
421 label_jump_to_a_project: Aller Γ  un projet...
423 label_file_plural: Fichiers
422 label_file_plural: Fichiers
424 label_changeset_plural: RΓ©visions
423 label_changeset_plural: RΓ©visions
425
424
426 button_login: Connexion
425 button_login: Connexion
427 button_submit: Soumettre
426 button_submit: Soumettre
428 button_save: Sauvegarder
427 button_save: Sauvegarder
429 button_check_all: Tout cocher
428 button_check_all: Tout cocher
430 button_uncheck_all: Tout dΓ©cocher
429 button_uncheck_all: Tout dΓ©cocher
431 button_delete: Supprimer
430 button_delete: Supprimer
432 button_create: CrΓ©er
431 button_create: CrΓ©er
433 button_test: Tester
432 button_test: Tester
434 button_edit: Modifier
433 button_edit: Modifier
435 button_add: Ajouter
434 button_add: Ajouter
436 button_change: Changer
435 button_change: Changer
437 button_apply: Appliquer
436 button_apply: Appliquer
438 button_clear: Effacer
437 button_clear: Effacer
439 button_lock: Verrouiller
438 button_lock: Verrouiller
440 button_unlock: DΓ©verrouiller
439 button_unlock: DΓ©verrouiller
441 button_download: TΓ©lΓ©charger
440 button_download: TΓ©lΓ©charger
442 button_list: Lister
441 button_list: Lister
443 button_view: Voir
442 button_view: Voir
444 button_move: DΓ©placer
443 button_move: DΓ©placer
445 button_back: Retour
444 button_back: Retour
446 button_cancel: Annuler
445 button_cancel: Annuler
447 button_activate: Activer
446 button_activate: Activer
448 button_sort: Trier
447 button_sort: Trier
449 button_log_time: Saisir temps
448 button_log_time: Saisir temps
450 button_rollback: Revenir Γ  cette version
449 button_rollback: Revenir Γ  cette version
451 button_watch: Surveiller
450 button_watch: Surveiller
452 button_unwatch: Ne plus surveiller
451 button_unwatch: Ne plus surveiller
453 button_reply: RΓ©pondre
452 button_reply: RΓ©pondre
454 button_archive: Archiver
453 button_archive: Archiver
455 button_unarchive: DΓ©sarchiver
454 button_unarchive: DΓ©sarchiver
456 button_reset: RΓ©initialiser
455 button_reset: RΓ©initialiser
457 button_rename: Renommer
456 button_rename: Renommer
458
457
459 status_active: actif
458 status_active: actif
460 status_registered: enregistrΓ©
459 status_registered: enregistrΓ©
461 status_locked: vΓ©rouillΓ©
460 status_locked: vΓ©rouillΓ©
462
461
463 text_select_mail_notifications: SΓ©lectionner les actions pour lesquelles la notification par mail doit Γͺtre activΓ©e.
462 text_select_mail_notifications: SΓ©lectionner les actions pour lesquelles la notification par mail doit Γͺtre activΓ©e.
464 text_regexp_info: ex. ^[A-Z0-9]+$
463 text_regexp_info: ex. ^[A-Z0-9]+$
465 text_min_max_length_info: 0 pour aucune restriction
464 text_min_max_length_info: 0 pour aucune restriction
466 text_project_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce projet et tout ce qui lui est rattachΓ© ?
465 text_project_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce projet et tout ce qui lui est rattachΓ© ?
467 text_workflow_edit: SΓ©lectionner un tracker et un rΓ΄le pour Γ©diter le workflow
466 text_workflow_edit: SΓ©lectionner un tracker et un rΓ΄le pour Γ©diter le workflow
468 text_are_you_sure: Etes-vous sΓ»r ?
467 text_are_you_sure: Etes-vous sΓ»r ?
469 text_journal_changed: changΓ© de %s Γ  %s
468 text_journal_changed: changΓ© de %s Γ  %s
470 text_journal_set_to: mis Γ  %s
469 text_journal_set_to: mis Γ  %s
471 text_journal_deleted: supprimΓ©
470 text_journal_deleted: supprimΓ©
472 text_tip_task_begin_day: tΓ’che commenΓ§ant ce jour
471 text_tip_task_begin_day: tΓ’che commenΓ§ant ce jour
473 text_tip_task_end_day: tΓ’che finissant ce jour
472 text_tip_task_end_day: tΓ’che finissant ce jour
474 text_tip_task_begin_end_day: tΓ’che commenΓ§ant et finissant ce jour
473 text_tip_task_begin_end_day: tΓ’che commenΓ§ant et finissant ce jour
475 text_project_identifier_info: 'Lettres minuscules (a-z), chiffres et tirets autorisΓ©s.<br />Un fois sauvegardΓ©, l''identifiant ne pourra plus Γͺtre modifiΓ©.'
474 text_project_identifier_info: 'Lettres minuscules (a-z), chiffres et tirets autorisΓ©s.<br />Un fois sauvegardΓ©, l''identifiant ne pourra plus Γͺtre modifiΓ©.'
476 text_caracters_maximum: %d caractères maximum.
475 text_caracters_maximum: %d caractères maximum.
477 text_length_between: Longueur comprise entre %d et %d caractères.
476 text_length_between: Longueur comprise entre %d et %d caractères.
478 text_tracker_no_workflow: Aucun worflow n'est dΓ©fini pour ce tracker
477 text_tracker_no_workflow: Aucun worflow n'est dΓ©fini pour ce tracker
479 text_unallowed_characters: Caractères non autorisés
478 text_unallowed_characters: Caractères non autorisés
480 text_comma_separated: Plusieurs valeurs possibles (sΓ©parΓ©es par des virgules).
479 text_comma_separated: Plusieurs valeurs possibles (sΓ©parΓ©es par des virgules).
481 text_issues_ref_in_commit_messages: RΓ©fΓ©rencement et rΓ©solution des demandes dans les commentaires de commits
480 text_issues_ref_in_commit_messages: RΓ©fΓ©rencement et rΓ©solution des demandes dans les commentaires de commits
482 text_issue_added: La demande %s a Γ©tΓ© soumise.
481 text_issue_added: La demande %s a Γ©tΓ© soumise.
483 text_issue_updated: La demande %s a Γ©tΓ© mise Γ  jour.
482 text_issue_updated: La demande %s a Γ©tΓ© mise Γ  jour.
484 text_wiki_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce wiki et tout son contenu ?
483 text_wiki_destroy_confirmation: Etes-vous sΓ»r de vouloir supprimer ce wiki et tout son contenu ?
485 text_issue_category_destroy_question: Des demandes (%d) sont affectΓ©es Γ  cette catΓ©gories. Que voulez-vous faire ?
484 text_issue_category_destroy_question: Des demandes (%d) sont affectΓ©es Γ  cette catΓ©gories. Que voulez-vous faire ?
486 text_issue_category_destroy_assignments: N'affecter les demandes Γ  aucune autre catΓ©gorie
485 text_issue_category_destroy_assignments: N'affecter les demandes Γ  aucune autre catΓ©gorie
487 text_issue_category_reassign_to: RΓ©affecter les demandes Γ  cette catΓ©gorie
486 text_issue_category_reassign_to: RΓ©affecter les demandes Γ  cette catΓ©gorie
488
487
489 default_role_manager: Manager
488 default_role_manager: Manager
490 default_role_developper: DΓ©veloppeur
489 default_role_developper: DΓ©veloppeur
491 default_role_reporter: Rapporteur
490 default_role_reporter: Rapporteur
492 default_tracker_bug: Anomalie
491 default_tracker_bug: Anomalie
493 default_tracker_feature: Evolution
492 default_tracker_feature: Evolution
494 default_tracker_support: Assistance
493 default_tracker_support: Assistance
495 default_issue_status_new: Nouveau
494 default_issue_status_new: Nouveau
496 default_issue_status_assigned: AssignΓ©
495 default_issue_status_assigned: AssignΓ©
497 default_issue_status_resolved: RΓ©solu
496 default_issue_status_resolved: RΓ©solu
498 default_issue_status_feedback: Commentaire
497 default_issue_status_feedback: Commentaire
499 default_issue_status_closed: FermΓ©
498 default_issue_status_closed: FermΓ©
500 default_issue_status_rejected: RejetΓ©
499 default_issue_status_rejected: RejetΓ©
501 default_doc_category_user: Documentation utilisateur
500 default_doc_category_user: Documentation utilisateur
502 default_doc_category_tech: Documentation technique
501 default_doc_category_tech: Documentation technique
503 default_priority_low: Bas
502 default_priority_low: Bas
504 default_priority_normal: Normal
503 default_priority_normal: Normal
505 default_priority_high: Haut
504 default_priority_high: Haut
506 default_priority_urgent: Urgent
505 default_priority_urgent: Urgent
507 default_priority_immediate: ImmΓ©diat
506 default_priority_immediate: ImmΓ©diat
508 default_activity_design: Conception
507 default_activity_design: Conception
509 default_activity_development: DΓ©veloppement
508 default_activity_development: DΓ©veloppement
510
509
511 enumeration_issue_priorities: PrioritΓ©s des demandes
510 enumeration_issue_priorities: PrioritΓ©s des demandes
512 enumeration_doc_categories: CatΓ©gories des documents
511 enumeration_doc_categories: CatΓ©gories des documents
513 enumeration_activities: ActivitΓ©s (suivi du temps)
512 enumeration_activities: ActivitΓ©s (suivi du temps)
1 NO CONTENT: file renamed from lib/redmine/acts_as_event/init.rb to lib/plugins/acts_as_event/init.rb
NO CONTENT: file renamed from lib/redmine/acts_as_event/init.rb to lib/plugins/acts_as_event/init.rb
1 NO CONTENT: file renamed from lib/redmine/acts_as_event/lib/acts_as_event.rb to lib/plugins/acts_as_event/lib/acts_as_event.rb
NO CONTENT: file renamed from lib/redmine/acts_as_event/lib/acts_as_event.rb to lib/plugins/acts_as_event/lib/acts_as_event.rb
1 NO CONTENT: file renamed from lib/redmine/acts_as_watchable/init.rb to lib/plugins/acts_as_watchable/init.rb
NO CONTENT: file renamed from lib/redmine/acts_as_watchable/init.rb to lib/plugins/acts_as_watchable/init.rb
1 NO CONTENT: file renamed from lib/redmine/acts_as_watchable/lib/acts_as_watchable.rb to lib/plugins/acts_as_watchable/lib/acts_as_watchable.rb
NO CONTENT: file renamed from lib/redmine/acts_as_watchable/lib/acts_as_watchable.rb to lib/plugins/acts_as_watchable/lib/acts_as_watchable.rb
@@ -1,103 +1,101
1 require 'redmine/access_control'
1 require 'redmine/access_control'
2 require 'redmine/menu_manager'
2 require 'redmine/menu_manager'
3 require 'redmine/mime_type'
3 require 'redmine/mime_type'
4 require 'redmine/acts_as_watchable/init'
5 require 'redmine/acts_as_event/init'
6 require 'redmine/plugin'
4 require 'redmine/plugin'
7
5
8 begin
6 begin
9 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
7 require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick)
10 rescue LoadError
8 rescue LoadError
11 # RMagick is not available
9 # RMagick is not available
12 end
10 end
13
11
14 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs )
12 REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs )
15
13
16 # Permissions
14 # Permissions
17 Redmine::AccessControl.map do |map|
15 Redmine::AccessControl.map do |map|
18 map.permission :view_project, {:projects => [:show, :activity, :feeds]}, :public => true
16 map.permission :view_project, {:projects => [:show, :activity, :feeds]}, :public => true
19 map.permission :search_project, {:search => :index}, :public => true
17 map.permission :search_project, {:search => :index}, :public => true
20 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
18 map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member
21 map.permission :select_project_modules, {:projects => :modules}, :require => :member
19 map.permission :select_project_modules, {:projects => :modules}, :require => :member
22 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
20 map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member
23 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
21 map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member
24
22
25 map.project_module :issue_tracking do |map|
23 map.project_module :issue_tracking do |map|
26 # Issue categories
24 # Issue categories
27 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
25 map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member
28 # Issues
26 # Issues
29 map.permission :view_issues, {:projects => [:list_issues, :export_issues_csv, :export_issues_pdf, :changelog, :roadmap],
27 map.permission :view_issues, {:projects => [:list_issues, :export_issues_csv, :export_issues_pdf, :changelog, :roadmap],
30 :issues => [:show, :export_pdf],
28 :issues => [:show, :export_pdf],
31 :queries => :index,
29 :queries => :index,
32 :reports => :issue_report}, :public => true
30 :reports => :issue_report}, :public => true
33 map.permission :add_issues, {:projects => :add_issue}, :require => :loggedin
31 map.permission :add_issues, {:projects => :add_issue}, :require => :loggedin
34 map.permission :edit_issues, {:issues => [:edit, :destroy_attachment]}, :require => :loggedin
32 map.permission :edit_issues, {:issues => [:edit, :destroy_attachment]}, :require => :loggedin
35 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}, :require => :loggedin
33 map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}, :require => :loggedin
36 map.permission :add_issue_notes, {:issues => :add_note}, :require => :loggedin
34 map.permission :add_issue_notes, {:issues => :add_note}, :require => :loggedin
37 map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin
35 map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin
38 map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin
36 map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin
39 map.permission :delete_issues, {:issues => :destroy}, :require => :member
37 map.permission :delete_issues, {:issues => :destroy}, :require => :member
40 # Queries
38 # Queries
41 map.permission :manage_pulic_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
39 map.permission :manage_pulic_queries, {:queries => [:new, :edit, :destroy]}, :require => :member
42 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
40 map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin
43 # Gantt & calendar
41 # Gantt & calendar
44 map.permission :view_gantt, :projects => :gantt
42 map.permission :view_gantt, :projects => :gantt
45 map.permission :view_calendar, :projects => :calendar
43 map.permission :view_calendar, :projects => :calendar
46 end
44 end
47
45
48 map.project_module :time_tracking do |map|
46 map.project_module :time_tracking do |map|
49 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
47 map.permission :log_time, {:timelog => :edit}, :require => :loggedin
50 map.permission :view_time_entries, :timelog => [:details, :report]
48 map.permission :view_time_entries, :timelog => [:details, :report]
51 end
49 end
52
50
53 map.project_module :news do |map|
51 map.project_module :news do |map|
54 map.permission :manage_news, {:projects => :add_news, :news => [:edit, :destroy, :destroy_comment]}, :require => :member
52 map.permission :manage_news, {:projects => :add_news, :news => [:edit, :destroy, :destroy_comment]}, :require => :member
55 map.permission :view_news, {:projects => :list_news, :news => :show}, :public => true
53 map.permission :view_news, {:projects => :list_news, :news => :show}, :public => true
56 map.permission :comment_news, {:news => :add_comment}, :require => :loggedin
54 map.permission :comment_news, {:news => :add_comment}, :require => :loggedin
57 end
55 end
58
56
59 map.project_module :documents do |map|
57 map.project_module :documents do |map|
60 map.permission :manage_documents, {:projects => :add_document, :documents => [:edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin
58 map.permission :manage_documents, {:projects => :add_document, :documents => [:edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin
61 map.permission :view_documents, :projects => :list_documents, :documents => [:show, :download]
59 map.permission :view_documents, :projects => :list_documents, :documents => [:show, :download]
62 end
60 end
63
61
64 map.project_module :files do |map|
62 map.project_module :files do |map|
65 map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin
63 map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin
66 map.permission :view_files, :projects => :list_files, :versions => :download
64 map.permission :view_files, :projects => :list_files, :versions => :download
67 end
65 end
68
66
69 map.project_module :wiki do |map|
67 map.project_module :wiki do |map|
70 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
68 map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member
71 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
69 map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member
72 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
70 map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member
73 map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :special]
71 map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :special]
74 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
72 map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment]
75 end
73 end
76
74
77 map.project_module :repository do |map|
75 map.project_module :repository do |map|
78 map.permission :manage_repository, :repositories => [:edit, :destroy]
76 map.permission :manage_repository, :repositories => [:edit, :destroy]
79 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :changes, :diff, :stats, :graph]
77 map.permission :browse_repository, :repositories => [:show, :browse, :entry, :changes, :diff, :stats, :graph]
80 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
78 map.permission :view_changesets, :repositories => [:show, :revisions, :revision]
81 end
79 end
82
80
83 map.project_module :boards do |map|
81 map.project_module :boards do |map|
84 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
82 map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member
85 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
83 map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true
86 map.permission :add_messages, {:messages => [:new, :reply]}, :require => :loggedin
84 map.permission :add_messages, {:messages => [:new, :reply]}, :require => :loggedin
87 end
85 end
88 end
86 end
89
87
90 # Project menu configuration
88 # Project menu configuration
91 Redmine::MenuManager.map :project_menu do |menu|
89 Redmine::MenuManager.map :project_menu do |menu|
92 menu.push :label_overview, :controller => 'projects', :action => 'show'
90 menu.push :label_overview, :controller => 'projects', :action => 'show'
93 menu.push :label_activity, :controller => 'projects', :action => 'activity'
91 menu.push :label_activity, :controller => 'projects', :action => 'activity'
94 menu.push :label_roadmap, :controller => 'projects', :action => 'roadmap'
92 menu.push :label_roadmap, :controller => 'projects', :action => 'roadmap'
95 menu.push :label_issue_plural, :controller => 'projects', :action => 'list_issues'
93 menu.push :label_issue_plural, :controller => 'projects', :action => 'list_issues'
96 menu.push :label_news_plural, :controller => 'projects', :action => 'list_news'
94 menu.push :label_news_plural, :controller => 'projects', :action => 'list_news'
97 menu.push :label_document_plural, :controller => 'projects', :action => 'list_documents'
95 menu.push :label_document_plural, :controller => 'projects', :action => 'list_documents'
98 menu.push :label_wiki, { :controller => 'wiki', :action => 'index', :page => nil }, :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
96 menu.push :label_wiki, { :controller => 'wiki', :action => 'index', :page => nil }, :if => Proc.new { |p| p.wiki && !p.wiki.new_record? }
99 menu.push :label_board_plural, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, :if => Proc.new { |p| p.boards.any? }
97 menu.push :label_board_plural, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, :if => Proc.new { |p| p.boards.any? }
100 menu.push :label_attachment_plural, :controller => 'projects', :action => 'list_files'
98 menu.push :label_attachment_plural, :controller => 'projects', :action => 'list_files'
101 menu.push :label_repository, { :controller => 'repositories', :action => 'show' }, :if => Proc.new { |p| p.repository && !p.repository.new_record? }
99 menu.push :label_repository, { :controller => 'repositories', :action => 'show' }, :if => Proc.new { |p| p.repository && !p.repository.new_record? }
102 menu.push :label_settings, :controller => 'projects', :action => 'settings'
100 menu.push :label_settings, :controller => 'projects', :action => 'settings'
103 end
101 end
@@ -1,49 +1,49
1 require File.dirname(__FILE__) + '/../test_helper'
1 require File.dirname(__FILE__) + '/../test_helper'
2 require 'search_controller'
2 require 'search_controller'
3
3
4 # Re-raise errors caught by the controller.
4 # Re-raise errors caught by the controller.
5 class SearchController; def rescue_action(e) raise e end; end
5 class SearchController; def rescue_action(e) raise e end; end
6
6
7 class SearchControllerTest < Test::Unit::TestCase
7 class SearchControllerTest < Test::Unit::TestCase
8 fixtures :projects, :issues
8 fixtures :projects, :issues
9
9
10 def setup
10 def setup
11 @controller = SearchController.new
11 @controller = SearchController.new
12 @request = ActionController::TestRequest.new
12 @request = ActionController::TestRequest.new
13 @response = ActionController::TestResponse.new
13 @response = ActionController::TestResponse.new
14 User.current = nil
14 User.current = nil
15 end
15 end
16
16
17 def test_search_for_projects
17 def test_search_for_projects
18 get :index
18 get :index
19 assert_response :success
19 assert_response :success
20 assert_template 'index'
20 assert_template 'index'
21
21
22 get :index, :q => "cook"
22 get :index, :q => "cook"
23 assert_response :success
23 assert_response :success
24 assert_template 'index'
24 assert_template 'index'
25 assert assigns(:results).include?(Project.find(1))
25 assert assigns(:results).include?(Project.find(1))
26 end
26 end
27
27
28 def test_search_in_project
28 def test_search_in_project
29 get :index, :id => 1
29 get :index, :id => 1
30 assert_response :success
30 assert_response :success
31 assert_template 'index'
31 assert_template 'index'
32 assert_not_nil assigns(:project)
32 assert_not_nil assigns(:project)
33
33
34 get :index, :id => 1, :q => "can", :scope => ["issues", "news", "documents"]
34 get :index, :id => 1, :q => "can"
35 assert_response :success
35 assert_response :success
36 assert_template 'index'
36 assert_template 'index'
37 end
37 end
38
38
39 def test_quick_jump_to_issue
39 def test_quick_jump_to_issue
40 # issue of a public project
40 # issue of a public project
41 get :index, :q => "3"
41 get :index, :q => "3"
42 assert_redirected_to 'issues/show/3'
42 assert_redirected_to 'issues/show/3'
43
43
44 # issue of a private project
44 # issue of a private project
45 get :index, :q => "4"
45 get :index, :q => "4"
46 assert_response :success
46 assert_response :success
47 assert_template 'index'
47 assert_template 'index'
48 end
48 end
49 end
49 end
General Comments 0
You need to be logged in to leave comments. Login now