Compare commits

..
1 Commits
Author SHA1 Message Date
Jean-Philippe Lang c021af8a1b tagged version 0.7.0-RC1
git-svn-id: http://redmine.rubyforge.org/svn/tags/0.7.0-RC1@1306 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-03-29 19:58:25 +00:00
140 changed files with 875 additions and 1937 deletions
-2
View File
@@ -56,8 +56,6 @@ class AccountController < ApplicationController
flash.now[:error] = l(:notice_account_invalid_creditentials) flash.now[:error] = l(:notice_account_invalid_creditentials)
end end
end end
rescue User::OnTheFlyCreationFailure
flash.now[:error] = 'Redmine could not retrieve the required information from the LDAP to create your account. Please, contact your Redmine administrator.'
end end
# Log out current user and redirect to welcome page # Log out current user and redirect to welcome page
-1
View File
@@ -150,7 +150,6 @@ class ApplicationController < ActionController::Base
def render_feed(items, options={}) def render_feed(items, options={})
@items = items || [] @items = items || []
@items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items.sort! {|x,y| y.event_datetime <=> x.event_datetime }
@items = @items.slice(0, Setting.feeds_limit.to_i)
@title = options[:title] || Setting.app_title @title = options[:title] || Setting.app_title
render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml' render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
end end
+4 -14
View File
@@ -73,8 +73,6 @@ class IssuesController < ApplicationController
# Send html if the query is not valid # Send html if the query is not valid
render(:template => 'issues/index.rhtml', :layout => !request.xhr?) render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
end end
rescue ActiveRecord::RecordNotFound
render_404
end end
def changes def changes
@@ -89,8 +87,6 @@ class IssuesController < ApplicationController
end end
@title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name)
render :layout => false, :content_type => 'application/atom+xml' render :layout => false, :content_type => 'application/atom+xml'
rescue ActiveRecord::RecordNotFound
render_404
end end
def show def show
@@ -140,9 +136,7 @@ class IssuesController < ApplicationController
requested_status = IssueStatus.find_by_id(params[:issue][:status_id]) requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
# Check that the user is allowed to apply the requested status # Check that the user is allowed to apply the requested status
@issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status @issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, @custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
:customized => @issue,
:value => (params[:custom_fields] ? params[:custom_fields][x.id.to_s] : nil)) }
@issue.custom_values = @custom_values @issue.custom_values = @custom_values
if @issue.save if @issue.save
attach_files(@issue, params[:attachments]) attach_files(@issue, params[:attachments])
@@ -344,8 +338,8 @@ class IssuesController < ApplicationController
end end
def preview def preview
@issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? issue = @project.issues.find_by_id(params[:id])
@attachements = @issue.attachments if @issue @attachements = issue.attachments if issue
@text = params[:notes] || (params[:issue] ? params[:issue][:description] : nil) @text = params[:notes] || (params[:issue] ? params[:issue][:description] : nil)
render :partial => 'common/preview' render :partial => 'common/preview'
end end
@@ -390,10 +384,7 @@ private
# Retrieve query from session or build a new query # Retrieve query from session or build a new query
def retrieve_query def retrieve_query
if !params[:query_id].blank? if !params[:query_id].blank?
cond = "project_id IS NULL" @query = Query.find(params[:query_id], :conditions => {:project_id => (@project ? @project.id : nil)})
cond << " OR project_id = #{@project.id}" if @project
@query = Query.find(params[:query_id], :conditions => cond)
@query.project = @project
session[:query] = {:id => @query.id, :project_id => @query.project_id} session[:query] = {:id => @query.id, :project_id => @query.project_id}
else else
if params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) if params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
@@ -413,7 +404,6 @@ private
else else
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id] @query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters]) @query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters])
@query.project = @project
end end
end end
end end
+6 -11
View File
@@ -66,20 +66,20 @@ class ProjectsController < ApplicationController
:conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}", :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
:order => 'name') :order => 'name')
@project = Project.new(params[:project]) @project = Project.new(params[:project])
@project.enabled_module_names = Redmine::AccessControl.available_project_modules
if request.get? if request.get?
@custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project) } @custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
@project.trackers = Tracker.all @project.trackers = Tracker.all
@project.is_public = Setting.default_projects_public? @project.is_public = Setting.default_projects_public?
@project.enabled_module_names = Redmine::AccessControl.available_project_modules
else else
@project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids] @project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
@custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => (params[:custom_fields] ? params["custom_fields"][x.id.to_s] : nil)) } @custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => (params[:custom_fields] ? params["custom_fields"][x.id.to_s] : nil)) }
@project.custom_values = @custom_values @project.custom_values = @custom_values
@project.enabled_module_names = params[:enabled_modules]
if @project.save if @project.save
@project.enabled_module_names = params[:enabled_modules]
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :controller => 'admin', :action => 'projects' redirect_to :controller => 'admin', :action => 'projects'
end end
end end
end end
@@ -204,10 +204,7 @@ class ProjectsController < ApplicationController
end end
def list_files def list_files
sort_init "#{Attachment.table_name}.filename", "asc" @versions = @project.versions.sort.reverse
sort_update
@versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
render :layout => !request.xhr?
end end
# Show changelog for @project # Show changelog for @project
@@ -341,9 +338,8 @@ class ProjectsController < ApplicationController
:include => [:tracker, :status, :assigned_to, :priority, :project], :include => [:tracker, :status, :assigned_to, :priority, :project],
:conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt]
) unless @selected_tracker_ids.empty? ) unless @selected_tracker_ids.empty?
events += Version.find(:all, :include => :project,
:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])
end end
events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])
@calendar.events = events @calendar.events = events
render :layout => false if request.xhr? render :layout => false if request.xhr?
@@ -387,9 +383,8 @@ class ProjectsController < ApplicationController
:include => [:tracker, :status, :assigned_to, :priority, :project], :include => [:tracker, :status, :assigned_to, :priority, :project],
:conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}))", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to] :conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}))", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to]
) unless @selected_tracker_ids.empty? ) unless @selected_tracker_ids.empty?
@events += Version.find(:all, :include => :project,
:conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
end end
@events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
@events.sort! {|x,y| x.start_date <=> y.start_date } @events.sort! {|x,y| x.start_date <=> y.start_date }
if params[:format]=='pdf' if params[:format]=='pdf'
+19 -18
View File
@@ -18,14 +18,19 @@
class QueriesController < ApplicationController class QueriesController < ApplicationController
layout 'base' layout 'base'
menu_item :issues menu_item :issues
before_filter :find_query, :except => :new before_filter :find_project, :authorize
before_filter :find_optional_project, :only => :new
def index
@queries = @project.queries.find(:all,
:order => "name ASC",
:conditions => ["is_public = ? or user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
end
def new def new
@query = Query.new(params[:query]) @query = Query.new(params[:query])
@query.project = params[:query_is_for_all] ? nil : @project @query.project = @project
@query.user = User.current @query.user = User.current
@query.is_public = false unless (@query.project && current_role.allowed_to?(:manage_public_queries)) || User.current.admin? @query.is_public = false unless current_role.allowed_to?(:manage_public_queries)
@query.column_names = nil if params[:default_columns] @query.column_names = nil if params[:default_columns]
params[:fields].each do |field| params[:fields].each do |field|
@@ -47,8 +52,7 @@ class QueriesController < ApplicationController
@query.add_filter(field, params[:operators][field], params[:values][field]) @query.add_filter(field, params[:operators][field], params[:values][field])
end if params[:fields] end if params[:fields]
@query.attributes = params[:query] @query.attributes = params[:query]
@query.project = nil if params[:query_is_for_all] @query.is_public = false unless current_role.allowed_to?(:manage_public_queries)
@query.is_public = false unless (@query.project && current_role.allowed_to?(:manage_public_queries)) || User.current.admin?
@query.column_names = nil if params[:default_columns] @query.column_names = nil if params[:default_columns]
if @query.save if @query.save
@@ -60,21 +64,18 @@ class QueriesController < ApplicationController
def destroy def destroy
@query.destroy if request.post? @query.destroy if request.post?
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 redirect_to :controller => 'queries', :project_id => @project
end end
private private
def find_query def find_project
@query = Query.find(params[:id]) if params[:id]
@project = @query.project @query = Query.find(params[:id])
render_403 unless @query.editable_by?(User.current) @project = @query.project
rescue ActiveRecord::RecordNotFound render_403 unless @query.editable_by?(User.current)
render_404 else
end @project = Project.find(params[:project_id])
end
def find_optional_project
@project = Project.find(params[:project_id]) if params[:project_id]
User.current.allowed_to?(:save_queries, @project, :global => true)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
+6 -21
View File
@@ -19,8 +19,8 @@ require 'SVG/Graph/Bar'
require 'SVG/Graph/BarHorizontal' require 'SVG/Graph/BarHorizontal'
require 'digest/sha1' require 'digest/sha1'
class ChangesetNotFound < Exception; end class ChangesetNotFound < Exception
class InvalidRevisionParam < Exception; end end
class RepositoriesController < ApplicationController class RepositoriesController < ApplicationController
layout 'base' layout 'base'
@@ -51,8 +51,8 @@ class RepositoriesController < ApplicationController
def show def show
# check if new revisions have been committed in the repository # check if new revisions have been committed in the repository
@repository.fetch_changesets if Setting.autofetch_changesets? @repository.fetch_changesets if Setting.autofetch_changesets?
# root entries # get entries for the browse frame
@entries = @repository.entries('', @rev) @entries = @repository.entries('')
# latest changesets # latest changesets
@changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC") @changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC")
show_error_not_found unless @entries || @changesets.any? show_error_not_found unless @entries || @changesets.any?
@@ -65,8 +65,7 @@ class RepositoriesController < ApplicationController
if request.xhr? if request.xhr?
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true) @entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
else else
show_error_not_found and return unless @entries show_error_not_found unless @entries
render :action => 'browse'
end end
rescue Redmine::Scm::Adapters::CommandFailed => e rescue Redmine::Scm::Adapters::CommandFailed => e
show_error_command_failed(e.message) show_error_command_failed(e.message)
@@ -96,12 +95,6 @@ class RepositoriesController < ApplicationController
end end
def entry def entry
@entry = @repository.scm.entry(@path, @rev)
show_error_not_found and return unless @entry
# If the entry is a dir, show the browser
browse and return if @entry.is_dir?
@content = @repository.scm.cat(@path, @rev) @content = @repository.scm.cat(@path, @rev)
show_error_not_found and return unless @content show_error_not_found and return unless @content
if 'raw' == params[:format] || @content.is_binary_data? if 'raw' == params[:format] || @content.is_binary_data?
@@ -142,6 +135,7 @@ class RepositoriesController < ApplicationController
end end
def diff def diff
@rev_to = params[:rev_to]
@diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
@diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
@@ -186,8 +180,6 @@ private
render_404 render_404
end end
REV_PARAM_RE = %r{^[a-f0-9]*$}
def find_repository def find_repository
@project = Project.find(params[:id]) @project = Project.find(params[:id])
@repository = @project.repository @repository = @project.repository
@@ -195,12 +187,8 @@ private
@path = params[:path].join('/') unless params[:path].nil? @path = params[:path].join('/') unless params[:path].nil?
@path ||= '' @path ||= ''
@rev = params[:rev] @rev = params[:rev]
@rev_to = params[:rev_to]
raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
rescue InvalidRevisionParam
show_error_not_found
end end
def show_error_not_found def show_error_not_found
@@ -267,9 +255,6 @@ private
commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10 changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
# Remove email adress in usernames
fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') }
graph = SVG::Graph::BarHorizontal.new( graph = SVG::Graph::BarHorizontal.new(
:height => 300, :height => 300,
:width => 500, :width => 500,
+109 -122
View File
@@ -26,8 +26,6 @@ class TimelogController < ApplicationController
include SortHelper include SortHelper
helper :issues helper :issues
include TimelogHelper include TimelogHelper
helper :custom_fields
include CustomFieldsHelper
def report def report
@available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", @available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id",
@@ -47,40 +45,37 @@ class TimelogController < ApplicationController
:label => :label_tracker}, :label => :label_tracker},
'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id",
:klass => Enumeration, :klass => Enumeration,
:label => :label_activity}, :label => :label_activity}
'issue' => {:sql => "#{TimeEntry.table_name}.issue_id",
:klass => Issue,
:label => :label_issue}
} }
# Add list and boolean custom fields as available criterias
@project.all_custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM custom_values c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = issues.id)",
:format => cf.field_format,
:label => cf.name}
end
@criterias = params[:criterias] || [] @criterias = params[:criterias] || []
@criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria} @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria}
@criterias.uniq! @criterias.uniq!
@criterias = @criterias[0,3] @criterias = @criterias[0,3]
@columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month' @columns = (params[:period] && %w(year month week).include?(params[:period])) ? params[:period] : 'month'
retrieve_date_range if params[:date_from]
begin; @date_from = params[:date_from].to_date; rescue; end
end
if params[:date_to]
begin; @date_to = params[:date_to].to_date; rescue; end
end
@date_from ||= Date.civil(Date.today.year, 1, 1)
@date_to ||= (Date.civil(Date.today.year, Date.today.month, 1) >> 1) - 1
unless @criterias.empty? unless @criterias.empty?
sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ') sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ')
sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ') sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ')
sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours" sql = "SELECT #{sql_select}, tyear, tmonth, tweek, SUM(hours) AS hours"
sql << " FROM #{TimeEntry.table_name}" sql << " FROM #{TimeEntry.table_name}"
sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id"
sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id"
sql << " WHERE (%s)" % @project.project_condition(Setting.display_subprojects_issues?) sql << " WHERE (%s)" % @project.project_condition(Setting.display_subprojects_issues?)
sql << " AND (%s)" % Project.allowed_to_condition(User.current, :view_time_entries) sql << " AND (%s)" % Project.allowed_to_condition(User.current, :view_time_entries)
sql << " AND spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@from.to_time), ActiveRecord::Base.connection.quoted_date(@to.to_time)] sql << " AND spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@date_from.to_time), ActiveRecord::Base.connection.quoted_date(@date_to.to_time)]
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on" sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek"
@hours = ActiveRecord::Base.connection.select_all(sql) @hours = ActiveRecord::Base.connection.select_all(sql)
@@ -92,122 +87,36 @@ class TimelogController < ApplicationController
row['month'] = "#{row['tyear']}-#{row['tmonth']}" row['month'] = "#{row['tyear']}-#{row['tmonth']}"
when 'week' when 'week'
row['week'] = "#{row['tyear']}-#{row['tweek']}" row['week'] = "#{row['tyear']}-#{row['tweek']}"
when 'day'
row['day'] = "#{row['spent_on']}"
end end
end end
@total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f}
end
@periods = [] @periods = []
# Date#at_beginning_of_ not supported in Rails 1.2.x date_from = @date_from
date_from = @from.to_time # 100 columns max
# 100 columns max while date_from < @date_to && @periods.length < 100
while date_from <= @to.to_time && @periods.length < 100 case @columns
case @columns when 'year'
when 'year' @periods << "#{date_from.year}"
@periods << "#{date_from.year}" date_from = date_from >> 12
date_from = (date_from + 1.year).at_beginning_of_year when 'month'
when 'month' @periods << "#{date_from.year}-#{date_from.month}"
@periods << "#{date_from.year}-#{date_from.month}" date_from = date_from >> 1
date_from = (date_from + 1.month).at_beginning_of_month when 'week'
when 'week' @periods << "#{date_from.year}-#{date_from.cweek}"
@periods << "#{date_from.year}-#{date_from.to_date.cweek}" date_from = date_from + 7
date_from = (date_from + 7.day).at_beginning_of_week
when 'day'
@periods << "#{date_from.to_date}"
date_from = date_from + 1.day
end
end end
end end
respond_to do |format| render :layout => false if request.xhr?
format.html { render :layout => !request.xhr? }
format.csv { send_data(report_to_csv(@criterias, @periods, @hours).read, :type => 'text/csv; header=present', :filename => 'timelog.csv') }
end
end end
def details def details
sort_init 'spent_on', 'desc' sort_init 'spent_on', 'desc'
sort_update sort_update
cond = ARCondition.new
cond << (@issue.nil? ? @project.project_condition(Setting.display_subprojects_issues?) :
["#{TimeEntry.table_name}.issue_id = ?", @issue.id])
retrieve_date_range
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
TimeEntry.visible_by(User.current) do
respond_to do |format|
format.html {
# Paginate results
@entry_count = TimeEntry.count(:include => :project, :conditions => cond.conditions)
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => :tracker}],
:conditions => cond.conditions,
:order => sort_clause,
:limit => @entry_pages.items_per_page,
:offset => @entry_pages.current.offset)
@total_hours = TimeEntry.sum(:hours, :include => :project, :conditions => cond.conditions).to_f
render :layout => !request.xhr?
}
format.csv {
# Export all entries
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:conditions => cond.conditions,
:order => sort_clause)
send_data(entries_to_csv(@entries).read, :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
end
end
def edit
render_403 and return if @time_entry && !@time_entry.editable_by?(User.current)
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry]
if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update)
redirect_to(params[:back_url] || {:action => 'details', :project_id => @time_entry.project})
return
end
@activities = Enumeration::get_values('ACTI')
end
def destroy
render_404 and return unless @time_entry
render_403 and return unless @time_entry.editable_by?(User.current)
@time_entry.destroy
flash[:notice] = l(:notice_successful_delete)
redirect_to :back
rescue RedirectBackError
redirect_to :action => 'details', :project_id => @time_entry.project
end
private
def find_project
if params[:id]
@time_entry = TimeEntry.find(params[:id])
@project = @time_entry.project
elsif params[:issue_id]
@issue = Issue.find(params[:issue_id])
@project = @issue.project
elsif params[:project_id]
@project = Project.find(params[:project_id])
else
render_404
return false
end
rescue ActiveRecord::RecordNotFound
render_404
end
# Retrieves the date range based on predefined ranges or specific from/to param dates
def retrieve_date_range
@free_period = false @free_period = false
@from, @to = nil, nil @from, @to = nil, nil
@@ -248,7 +157,85 @@ private
end end
@from, @to = @to, @from if @from && @to && @from > @to @from, @to = @to, @from if @from && @to && @from > @to
@from ||= (TimeEntry.minimum(:spent_on, :include => :project, :conditions => @project.project_condition(Setting.display_subprojects_issues?)) || Date.today) - 1
@to ||= (TimeEntry.maximum(:spent_on, :include => :project, :conditions => @project.project_condition(Setting.display_subprojects_issues?)) || Date.today) cond = ARCondition.new
cond << (@issue.nil? ? @project.project_condition(Setting.display_subprojects_issues?) :
["#{TimeEntry.table_name}.issue_id = ?", @issue.id])
if @from
if @to
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
else
cond << ['spent_on >= ?', @from]
end
elsif @to
cond << ['spent_on <= ?', @to]
end
TimeEntry.visible_by(User.current) do
respond_to do |format|
format.html {
# Paginate results
@entry_count = TimeEntry.count(:include => :project, :conditions => cond.conditions)
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => :tracker}],
:conditions => cond.conditions,
:order => sort_clause,
:limit => @entry_pages.items_per_page,
:offset => @entry_pages.current.offset)
@total_hours = TimeEntry.sum(:hours, :include => :project, :conditions => cond.conditions).to_f
render :layout => !request.xhr?
}
format.csv {
# Export all entries
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:conditions => cond.conditions,
:order => sort_clause)
send_data(entries_to_csv(@entries).read, :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
end
end
def edit
render_403 and return if @time_entry && !@time_entry.editable_by?(User.current)
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry]
if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'details', :project_id => @time_entry.project
return
end
@activities = Enumeration::get_values('ACTI')
end
def destroy
render_404 and return unless @time_entry
render_403 and return unless @time_entry.editable_by?(User.current)
@time_entry.destroy
flash[:notice] = l(:notice_successful_delete)
redirect_to :back
rescue RedirectBackError
redirect_to :action => 'details', :project_id => @time_entry.project
end
private
def find_project
if params[:id]
@time_entry = TimeEntry.find(params[:id])
@project = @time_entry.project
elsif params[:issue_id]
@issue = Issue.find(params[:issue_id])
@project = @issue.project
elsif params[:project_id]
@project = Project.find(params[:project_id])
else
render_404
return false
end
rescue ActiveRecord::RecordNotFound
render_404
end end
end end
+1 -2
View File
@@ -83,8 +83,7 @@ class UsersController < ApplicationController
end end
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
# Give a string to redirect_to otherwise it would use status param as the response code redirect_to :action => 'list'
redirect_to(url_for(:action => 'list', :status => params[:status], :page => params[:page]))
end end
end end
@auth_sources = AuthSource.find(:all) @auth_sources = AuthSource.find(:all)
+2 -21
View File
@@ -207,10 +207,8 @@ module ApplicationHelper
rf = Regexp.new(filename, Regexp::IGNORECASE) rf = Regexp.new(filename, Regexp::IGNORECASE)
# search for the picture in attachments # search for the picture in attachments
if found = attachments.detect { |att| att.filename =~ rf } if found = attachments.detect { |att| att.filename =~ rf }
image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found.id
desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1") "!#{style}#{image_url}!"
alt = desc.blank? ? nil : "(#{desc})"
"!#{style}#{image_url}#{alt}!"
else else
"!#{style}#{filename}!" "!#{style}#{filename}!"
end end
@@ -427,10 +425,6 @@ module ApplicationHelper
form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
end end
def back_url_hidden_field_tag
hidden_field_tag 'back_url', (params[:back_url] || request.env['HTTP_REFERER'])
end
def check_all_links(form_name) def check_all_links(form_name)
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
" | " + " | " +
@@ -469,23 +463,10 @@ module ApplicationHelper
end end
def calendar_for(field_id) def calendar_for(field_id)
include_calendar_headers_tags
image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });") javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
end end
def include_calendar_headers_tags
unless @calendar_headers_tags_included
@calendar_headers_tags_included = true
content_for :header_tags do
javascript_include_tag('calendar/calendar') +
javascript_include_tag("calendar/lang/calendar-#{current_language}.js") +
javascript_include_tag('calendar/calendar-setup') +
stylesheet_link_tag('calendar')
end
end
end
def wikitoolbar_for(field_id) def wikitoolbar_for(field_id)
return '' unless Setting.text_formatting == 'textile' return '' unless Setting.text_formatting == 'textile'
-13
View File
@@ -33,19 +33,6 @@ module IssuesHelper
"<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}" "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
end end
def sidebar_queries
unless @sidebar_queries
# User can see public queries and his own queries
visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
# Project specific queries and global queries
visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
@sidebar_queries = Query.find(:all,
:order => "name ASC",
:conditions => visible.conditions)
end
@sidebar_queries
end
def show_detail(detail, no_html=false) def show_detail(detail, no_html=false)
case detail.property case detail.property
when 'attr' when 'attr'
+2 -5
View File
@@ -58,11 +58,8 @@ module RepositoriesHelper
end end
def with_leading_slash(path) def with_leading_slash(path)
path.to_s.starts_with?('/') ? path : "/#{path}" path ||= ''
end path.starts_with?('/') ? path : "/#{path}"
def without_leading_slash(path)
path.gsub(%r{^/+}, '')
end end
def subversion_field_tags(form, repository) def subversion_field_tags(form, repository)
-56
View File
@@ -76,60 +76,4 @@ module TimelogHelper
export.rewind export.rewind
export export
end end
def format_criteria_value(criteria, value)
value.blank? ? l(:label_none) : ((k = @available_criterias[criteria][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criterias[criteria][:format]))
end
def report_to_csv(criterias, periods, hours)
export = StringIO.new
CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
# Column headers
headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
headers += periods
headers << l(:label_total)
csv << headers.collect {|c| to_utf8(c) }
# Content
report_criteria_to_csv(csv, criterias, periods, hours)
# Total row
row = [ l(:label_total) ] + [''] * (criterias.size - 1)
total = 0
periods.each do |period|
sum = sum_hours(select_hours(hours, @columns, period.to_s))
total += sum
row << (sum > 0 ? "%.2f" % sum : '')
end
row << "%.2f" %total
csv << row
end
export.rewind
export
end
def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value|
hours_for_value = select_hours(hours, criterias[level], value)
next if hours_for_value.empty?
row = [''] * level
row << to_utf8(format_criteria_value(criterias[level], value))
row += [''] * (criterias.length - level - 1)
total = 0
periods.each do |period|
sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s))
total += sum
row << (sum > 0 ? "%.2f" % sum : '')
end
row << "%.2f" %total
csv << row
if criterias.length > level + 1
report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
end
end
end
def to_utf8(s)
@ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8')
begin; @ic.iconv(s.to_s); rescue; s.to_s; end
end
end end
-12
View File
@@ -22,16 +22,4 @@ module UsersHelper
[l(:status_registered), 2], [l(:status_registered), 2],
[l(:status_locked), 3]], selected) [l(:status_locked), 3]], selected)
end end
def change_status_link(user)
url = {:action => 'edit', :id => user, :page => params[:page], :status => params[:status]}
if user.locked?
link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'
elsif user.registered?
link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'
else
link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :post, :class => 'icon icon-lock'
end
end
end end
+46 -45
View File
@@ -35,48 +35,48 @@ class Attachment < ActiveRecord::Base
errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
end end
def file=(incoming_file) def file=(incomming_file)
unless incoming_file.nil? unless incomming_file.nil?
@temp_file = incoming_file @temp_file = incomming_file
if @temp_file.size > 0 if @temp_file.size > 0
self.filename = sanitize_filename(@temp_file.original_filename) self.filename = sanitize_filename(@temp_file.original_filename)
self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
self.content_type = @temp_file.content_type.to_s.chomp self.content_type = @temp_file.content_type.to_s.chomp
self.filesize = @temp_file.size self.filesize = @temp_file.size
end end
end end
end end
def file def file
nil nil
end end
# Copy temp file to its final location # Copy temp file to its final location
def before_save def before_save
if @temp_file && (@temp_file.size > 0) if @temp_file && (@temp_file.size > 0)
logger.debug("saving '#{self.diskfile}'") logger.debug("saving '#{self.diskfile}'")
File.open(diskfile, "wb") do |f| File.open(diskfile, "wb") do |f|
f.write(@temp_file.read) f.write(@temp_file.read)
end end
self.digest = Digest::MD5.hexdigest(File.read(diskfile)) self.digest = Digest::MD5.hexdigest(File.read(diskfile))
end end
# Don't save the content type if it's longer than the authorized length # Don't save the content type if it's longer than the authorized length
if self.content_type && self.content_type.length > 255 if self.content_type && self.content_type.length > 255
self.content_type = nil self.content_type = nil
end end
end end
# Deletes file on the disk # Deletes file on the disk
def after_destroy def after_destroy
if self.filename? if self.filename?
File.delete(diskfile) if File.exist?(diskfile) File.delete(diskfile) if File.exist?(diskfile)
end end
end end
# Returns file's location on disk # Returns file's location on disk
def diskfile def diskfile
"#{@@storage_path}/#{self.disk_filename}" "#{@@storage_path}/#{self.disk_filename}"
end end
def increment_download def increment_download
increment!(:downloads) increment!(:downloads)
@@ -87,17 +87,18 @@ class Attachment < ActiveRecord::Base
end end
def image? def image?
self.filename =~ /\.(jpe?g|gif|png)$/i self.filename =~ /\.(jpeg|jpg|gif|png)$/i
end end
private private
def sanitize_filename(value) def sanitize_filename(value)
# get only the filename, not the whole path # get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '') just_filename = value.gsub(/^.*(\\|\/)/, '')
# NOTE: File.basename doesn't work right with Windows paths on Unix # NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
# Finally, replace all non alphanumeric, hyphens or periods with underscore # Finally, replace all non alphanumeric, underscore or periods with underscore
@filename = just_filename.gsub(/[^\w\.\-]/,'_') @filename = just_filename.gsub(/[^\w\.\-]/,'_')
end end
end end
-4
View File
@@ -35,10 +35,6 @@ class Changeset < ActiveRecord::Base
validates_uniqueness_of :revision, :scope => :repository_id validates_uniqueness_of :revision, :scope => :repository_id
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
def revision=(r)
write_attribute :revision, (r.nil? ? nil : r.to_s)
end
def comments=(comment) def comments=(comment)
write_attribute(:comments, comment.strip) write_attribute(:comments, comment.strip)
end end
-10
View File
@@ -94,10 +94,6 @@ class Issue < ActiveRecord::Base
write_attribute(:priority_id, pid) write_attribute(:priority_id, pid)
end end
def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
end
def validate def validate
if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
errors.add :due_date, :activerecord_error_not_a_date errors.add :due_date, :activerecord_error_not_a_date
@@ -157,8 +153,6 @@ class Issue < ActiveRecord::Base
# Close duplicates if the issue was closed # Close duplicates if the issue was closed
if @issue_before_change && !@issue_before_change.closed? && self.closed? if @issue_before_change && !@issue_before_change.closed? && self.closed?
duplicates.each do |duplicate| duplicates.each do |duplicate|
# Reload is need in case the duplicate was updated by a previous duplicate
duplicate.reload
# Don't re-close it if it's already closed # Don't re-close it if it's already closed
next if duplicate.closed? next if duplicate.closed?
# Same user and notes # Same user and notes
@@ -243,8 +237,4 @@ class Issue < ActiveRecord::Base
yield yield
end end
end end
def to_s
"#{tracker} ##{id}: #{subject}"
end
end end
-1
View File
@@ -33,7 +33,6 @@ class Journal < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{o.issue.tracker.name} ##{o.issue.id}: #{o.issue.subject}" + ((s = o.new_status) ? " (#{s})" : '') }, acts_as_event :title => Proc.new {|o| "#{o.issue.tracker.name} ##{o.issue.id}: #{o.issue.subject}" + ((s = o.new_status) ? " (#{s})" : '') },
:description => :notes, :description => :notes,
:author => :user, :author => :user,
:type => Proc.new {|o| (s = o.new_status) && s.is_closed? ? 'issue-closed' : 'issue-edit' },
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}} :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}}
def save def save
-1
View File
@@ -28,7 +28,6 @@ class Message < ActiveRecord::Base
:date_column => 'created_on' :date_column => 'created_on'
acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
:description => :content, :description => :content,
:type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},
:url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id, :id => o.id}} :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id, :id => o.id}}
attr_protected :locked, :sticky attr_protected :locked, :sticky
-2
View File
@@ -21,8 +21,6 @@ class MessageObserver < ActiveRecord::Observer
recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?} recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?}
# send notification to the board watchers # send notification to the board watchers
recipients += message.board.watcher_recipients recipients += message.board.watcher_recipients
# send notification to project members who want to be notified
recipients += message.board.project.recipients
recipients = recipients.compact.uniq recipients = recipients.compact.uniq
Mailer.deliver_message_posted(message, recipients) if !recipients.empty? && Setting.notified_events.include?('message_posted') Mailer.deliver_message_posted(message, recipients) if !recipients.empty? && Setting.notified_events.include?('message_posted')
end end
+4 -6
View File
@@ -33,7 +33,7 @@ class Project < ActiveRecord::Base
has_many :documents, :dependent => :destroy has_many :documents, :dependent => :destroy
has_many :news, :dependent => :delete_all, :include => :author has_many :news, :dependent => :delete_all, :include => :author
has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name" has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
has_many :boards, :dependent => :destroy, :order => "position ASC" has_many :boards, :order => "position ASC"
has_one :repository, :dependent => :destroy has_one :repository, :dependent => :destroy
has_many :changesets, :through => :repository has_many :changesets, :through => :repository
has_one :wiki, :dependent => :destroy has_one :wiki, :dependent => :destroy
@@ -75,14 +75,12 @@ class Project < ActiveRecord::Base
conditions = nil conditions = nil
if include_subprojects && !active_children.empty? if include_subprojects && !active_children.empty?
ids = [id] + active_children.collect {|c| c.id} ids = [id] + active_children.collect {|c| c.id}
conditions = ["#{Project.table_name}.id IN (#{ids.join(',')})"] conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
end end
conditions ||= ["#{Project.table_name}.id = ?", id] conditions ||= ["#{Issue.table_name}.project_id = ?", id]
# Quick and dirty fix for Rails 2 compatibility # Quick and dirty fix for Rails 2 compatibility
Issue.send(:with_scope, :find => { :conditions => conditions }) do Issue.send(:with_scope, :find => { :conditions => conditions }) do
Version.send(:with_scope, :find => { :conditions => conditions }) do yield
yield
end
end end
end end
+6 -13
View File
@@ -116,11 +116,6 @@ class Query < ActiveRecord::Base
set_language_if_valid(User.current.language) set_language_if_valid(User.current.language)
end end
def after_initialize
# Store the fact that project is nil (used in #editable_by?)
@is_for_all = project.nil?
end
def validate def validate
filters.each_key do |field| filters.each_key do |field|
errors.add label_for(field), :activerecord_error_blank unless errors.add label_for(field), :activerecord_error_blank unless
@@ -133,10 +128,8 @@ class Query < ActiveRecord::Base
def editable_by?(user) def editable_by?(user)
return false unless user return false unless user
# Admin can edit them all and regular users can edit their private queries return true if !is_public && self.user_id == user.id
return true if user.admin? || (!is_public && self.user_id == user.id) is_public && user.allowed_to?(:manage_public_queries, project)
# Members can not edit public queries that are for all project (only admin is allowed to)
is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project)
end end
def available_filters def available_filters
@@ -146,7 +139,7 @@ class Query < ActiveRecord::Base
@available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } }, @available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
"tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } }, "tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },
"priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI'], :order => 'position').collect{|s| [s.name, s.id.to_s] } }, "priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect{|s| [s.name, s.id.to_s] } },
"subject" => { :type => :text, :order => 8 }, "subject" => { :type => :text, :order => 8 },
"created_on" => { :type => :date_past, :order => 9 }, "created_on" => { :type => :date_past, :order => 9 },
"updated_on" => { :type => :date_past, :order => 10 }, "updated_on" => { :type => :date_past, :order => 10 },
@@ -301,7 +294,7 @@ class Query < ActiveRecord::Base
# custom field # custom field
db_table = CustomValue.table_name db_table = CustomValue.table_name
db_field = 'value' db_field = 'value'
sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE " sql << "#{Issue.table_name}.id IN (SELECT #{db_table}.customized_id FROM #{db_table} where #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} AND "
else else
# regular field # regular field
db_table = Issue.table_name db_table = Issue.table_name
@@ -320,9 +313,9 @@ class Query < ActiveRecord::Base
when "!" when "!"
sql = sql + "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" sql = sql + "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
when "!*" when "!*"
sql = sql + "#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} = ''" sql = sql + "#{db_table}.#{db_field} IS NULL"
when "*" when "*"
sql = sql + "#{db_table}.#{db_field} IS NOT NULL AND #{db_table}.#{db_field} <> ''" sql = sql + "#{db_table}.#{db_field} IS NOT NULL"
when ">=" when ">="
sql = sql + "#{db_table}.#{db_field} >= #{v.first.to_i}" sql = sql + "#{db_table}.#{db_field} >= #{v.first.to_i}"
when "<=" when "<="
+5 -12
View File
@@ -35,8 +35,7 @@ class Repository::Cvs < Repository
end end
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
rev = identifier.nil? ? nil : changesets.find_by_revision(identifier) entries=scm.entries(path, identifier)
entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
if entries if entries
entries.each() do |entry| entries.each() do |entry|
unless entry.lastrev.nil? || entry.lastrev.identifier unless entry.lastrev.nil? || entry.lastrev.identifier
@@ -138,18 +137,12 @@ class Repository::Cvs < Repository
end end
# Renumber new changesets in chronological order # Renumber new changesets in chronological order
c = changesets.find(:first, :order => 'committed_on DESC, id DESC', :conditions => "revision NOT LIKE '_%'")
next_rev = c.nil? ? 1 : (c.revision.to_i + 1)
changesets.find(:all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE '_%'").each do |changeset| changesets.find(:all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE '_%'").each do |changeset|
changeset.update_attribute :revision, next_revision_number changeset.update_attribute :revision, next_rev
next_rev += 1
end end
end # transaction end # transaction
end end
private
# Returns the next revision number to assign to a CVS changeset
def next_revision_number
# Need to retrieve existing revision numbers to sort them as integers
@current_revision_number ||= (connection.select_values("SELECT revision FROM #{Changeset.table_name} WHERE repository_id = #{id} AND revision NOT LIKE '_%'").collect(&:to_i).max || 0)
@current_revision_number += 1
end
end end
+1 -2
View File
@@ -29,8 +29,7 @@ class Repository::Darcs < Repository
end end
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
patch = identifier.nil? ? nil : changesets.find_by_revision(identifier) entries=scm.entries(path, identifier)
entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
if entries if entries
entries.each do |entry| entries.each do |entry|
# Search the DB for the entry's last change # Search the DB for the entry's last change
+1 -8
View File
@@ -34,11 +34,6 @@ class Repository::Mercurial < Repository
if entries if entries
entries.each do |entry| entries.each do |entry|
next unless entry.is_file? next unless entry.is_file?
# Set the filesize unless browsing a specific revision
if identifier.nil?
full_path = File.join(root_url, entry.path)
entry.size = File.stat(full_path).size if File.file?(full_path)
end
# Search the DB for the entry's last change # Search the DB for the entry's last change
change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC") change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC")
if change if change
@@ -58,9 +53,7 @@ class Repository::Mercurial < Repository
# latest revision found in database # latest revision found in database
db_revision = latest_changeset ? latest_changeset.revision.to_i : -1 db_revision = latest_changeset ? latest_changeset.revision.to_i : -1
# latest revision in the repository # latest revision in the repository
latest_revision = scm_info.lastrev scm_revision = scm_info.lastrev.identifier.to_i
return if latest_revision.nil?
scm_revision = latest_revision.identifier.to_i
if db_revision < scm_revision if db_revision < scm_revision
logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
identifier_from = db_revision + 1 identifier_from = db_revision + 1
+1 -5
View File
@@ -1,5 +1,5 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2008 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -39,10 +39,6 @@ class TimeEntry < ActiveRecord::Base
errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project) errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project)
end end
def hours=(h)
write_attribute :hours, (h.is_a?(String) ? h.to_hours : h)
end
# tyear, tmonth, tweek assigned where setting spent_on attributes # tyear, tmonth, tweek assigned where setting spent_on attributes
# these attributes make time aggregations easier # these attributes make time aggregations easier
def spent_on=(date) def spent_on=(date)
+14 -28
View File
@@ -18,9 +18,6 @@
require "digest/sha1" require "digest/sha1"
class User < ActiveRecord::Base class User < ActiveRecord::Base
class OnTheFlyCreationFailure < Exception; end
# Account statuses # Account statuses
STATUS_ANONYMOUS = 0 STATUS_ANONYMOUS = 0
STATUS_ACTIVE = 1 STATUS_ACTIVE = 1
@@ -108,17 +105,15 @@ class User < ActiveRecord::Base
onthefly.language = Setting.default_language onthefly.language = Setting.default_language
if onthefly.save if onthefly.save
user = find(:first, :conditions => ["login=?", login]) user = find(:first, :conditions => ["login=?", login])
logger.info("User '#{user.login}' created from the LDAP") if logger logger.info("User '#{user.login}' created on the fly.") if logger
else
logger.error("User '#{onthefly.login}' found in LDAP but could not be created (#{onthefly.errors.full_messages.join(', ')})") if logger
raise OnTheFlyCreationFailure.new
end end
end end
end end
user.update_attribute(:last_login_on, Time.now) if user user.update_attribute(:last_login_on, Time.now) if user
user user
rescue => text
raise text rescue => text
raise text
end end
# Return user's full name for display # Return user's full name for display
@@ -227,26 +222,17 @@ class User < ActiveRecord::Base
# action can be: # action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
# * a permission Symbol (eg. :edit_project) # * a permission Symbol (eg. :edit_project)
def allowed_to?(action, project, options={}) def allowed_to?(action, project)
if project # No action allowed on archived projects
# No action allowed on archived projects return false unless project.active?
return false unless project.active? # No action allowed on disabled modules
# No action allowed on disabled modules return false unless project.allows_to?(action)
return false unless project.allows_to?(action) # Admin users are authorized for anything else
# Admin users are authorized for anything else return true if admin?
return true if admin?
role = role_for_project(project) role = role_for_project(project)
return false unless role return false unless role
role.allowed_to?(action) && (project.is_public? || role.member?) role.allowed_to?(action) && (project.is_public? || role.member?)
elsif options[:global]
# authorize if user has at least one role that has this permission
roles = memberships.collect {|m| m.role}.uniq
roles.detect {|r| r.allowed_to?(action)}
else
false
end
end end
def self.current=(user) def self.current=(user)
-1
View File
@@ -32,7 +32,6 @@ class WikiContent < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"},
:description => :comments, :description => :comments,
:datetime => :updated_on, :datetime => :updated_on,
:type => 'wiki-page',
:url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}} :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
def text=(plain) def text=(plain)
+7
View File
@@ -35,3 +35,10 @@
<%= submit_tag l(:button_submit) %> <%= submit_tag l(:button_submit) %>
<% end %> <% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+2 -5
View File
@@ -19,15 +19,12 @@ while day <= calendar.enddt %>
elsif day == i.due_date elsif day == i.due_date
image_tag('arrow_to.png') image_tag('arrow_to.png')
end %> end %>
<%= h("#{i.project} -") unless @project && @project == i.project %> <%= h("#{i.project.name} -") unless @project && @project == i.project %>
<%= link_to_issue i %>: <%= h(truncate(i.subject, 30)) %> <%= link_to_issue i %>: <%= h(truncate(i.subject, 30)) %>
<span class="tip"><%= render_issue_tooltip i %></span> <span class="tip"><%= render_issue_tooltip i %></span>
</div> </div>
<% else %> <% else %>
<span class="icon icon-package"> <%= link_to_version i, :class => "icon icon-package" %>
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i%>
</span>
<% end %> <% end %>
<% end %> <% end %>
</td> </td>
+7
View File
@@ -49,3 +49,10 @@
<% end %> <% end %>
<%= wikitoolbar_for 'issue_description' %> <%= wikitoolbar_for 'issue_description' %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+1 -1
View File
@@ -1,5 +1,5 @@
<% for journal in journals %> <% for journal in journals %>
<div id="change-<%= journal.id %>" class="journal"> <div id="change-<%= journal.id %>">
<h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div> <h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
<%= content_tag('a', '', :name => "note-#{journal.indice}")%> <%= content_tag('a', '', :name => "note-#{journal.indice}")%>
<%= format_time(journal.created_on) %> - <%= journal.user.name %></h4> <%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>
+5 -6
View File
@@ -1,14 +1,13 @@
<h3><%= l(:label_issue_plural) %></h3> <h3><%= l(:label_issue_plural) %></h3>
<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %><br /> <%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %><br />
<% if @project %>
<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %><br /> <%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %><br />
<%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %> <%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %>
<% end %>
<% unless sidebar_queries.empty? -%>
<h3><%= l(:label_query_plural) %></h3> <h3><%= l(:label_query_plural) %></h3>
<% sidebar_queries.each do |query| -%> <% queries = @project.queries.find(:all,
:order => "name ASC",
:conditions => ["is_public = ? or user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
queries.each do |query| %>
<%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %><br /> <%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %><br />
<% end -%> <% end %>
<% end -%>
+7
View File
@@ -47,3 +47,10 @@
<p><%= submit_tag l(:button_submit) %> <p><%= submit_tag l(:button_submit) %>
<% end %> <% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+2 -2
View File
@@ -18,7 +18,7 @@
:update => "content", :update => "content",
}, :class => 'icon icon-reload' %> }, :class => 'icon icon-reload' %>
<% if User.current.allowed_to?(:save_queries, @project, :global => true) %> <% if current_role && current_role.allowed_to?(:save_queries) %>
<%= link_to l(:button_save), {}, :onclick => "$('query_form').submit(); return false;", :class => 'icon icon-save' %> <%= link_to l(:button_save), {}, :onclick => "$('query_form').submit(); return false;", :class => 'icon icon-save' %>
<% end %> <% end %>
</p> </p>
@@ -54,7 +54,7 @@
<% content_for :sidebar do %> <% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %> <%= render :partial => 'issues/sidebar' %>
<% end %> <% end if @project%>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %> <%= auto_discovery_link_tag(:atom, {:query_id => @query, :format => 'atom', :page => nil, :key => User.current.rss_key}, :title => l(:label_issue_plural)) %>
+1 -1
View File
@@ -8,7 +8,7 @@
</div> </div>
<%= submit_tag l(:button_create) %> <%= submit_tag l(:button_create) %>
<%= link_to_remote l(:label_preview), <%= link_to_remote l(:label_preview),
{ :url => { :controller => 'issues', :action => 'preview', :project_id => @project }, { :url => { :controller => 'issues', :action => 'preview', :project_id => @project, :id => @issue },
:method => 'post', :method => 'post',
:update => 'preview', :update => 'preview',
:with => "Form.serialize('issue-form')", :with => "Form.serialize('issue-form')",
+1 -1
View File
@@ -13,7 +13,7 @@
<h3><%=h @issue.subject %></h3> <h3><%=h @issue.subject %></h3>
<p class="author"> <p class="author">
<%= authoring @issue.created_on, @issue.author %>. <%= authoring @issue.created_on, @issue.author %>.
<%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) + '.' if @issue.created_on != @issue.updated_on %> <%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) if @issue.created_on != @issue.updated_on %>.
</p> </p>
<table width="100%"> <table width="100%">
+1 -1
View File
@@ -26,7 +26,7 @@
</div> </div>
<div class="message reply"> <div class="message reply">
<h4><%=h message.subject %> - <%= authoring message.created_on, message.author %></h4> <h4><%=h message.subject %> - <%= authoring message.created_on, message.author %></h4>
<div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div> <div class="wiki"><%= textilizable message.content %></div>
<%= link_to_attachments message.attachments, :no_author => true %> <%= link_to_attachments message.attachments, :no_author => true %>
</div> </div>
<% end %> <% end %>
+1 -1
View File
@@ -25,7 +25,7 @@
<div id="preview" class="wiki"></div> <div id="preview" class="wiki"></div>
</div> </div>
<p><em><% unless @news.summary.blank? %><%=h @news.summary %><br /><% end %> <p><em><% unless @news.summary.empty? %><%=h @news.summary %><br /><% end %>
<span class="author"><%= authoring @news.created_on, @news.author %></span></em></p> <span class="author"><%= authoring @news.created_on, @news.author %></span></em></p>
<div class="wiki"> <div class="wiki">
<%= textilizable(@news.description) %> <%= textilizable(@news.description) %>
+8
View File
@@ -46,3 +46,11 @@
</fieldset> </fieldset>
<% end %> <% end %>
<!--[eoform:project]--> <!--[eoform:project]-->
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+1 -1
View File
@@ -6,7 +6,7 @@
<h3><%= format_activity_day(day) %></h3> <h3><%= format_activity_day(day) %></h3>
<dl> <dl>
<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
<dt class="<%= e.event_type %>"><span class="time"><%= format_time(e.event_datetime, false) %></span> <dt class="<%= e.class.name.downcase %>"><span class="time"><%= format_time(e.event_datetime, false) %></span>
<%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to h(truncate(e.event_title, 100)), e.event_url %></dt> <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to h(truncate(e.event_title, 100)), e.event_url %></dt>
<dd><% unless e.event_description.blank? -%> <dd><% unless e.event_description.blank? -%>
<span class="description"><%= format_activity_description(e.event_description) %></span><br /> <span class="description"><%= format_activity_description(e.event_description) %></span><br />
+6 -8
View File
@@ -1,16 +1,14 @@
<h2><%=l(:label_confirmation)%></h2> <h2><%=l(:label_confirmation)%></h2>
<div class="warning"> <div class="box">
<p><strong><%=h @project_to_destroy %></strong><br /> <center>
<%=l(:text_project_destroy_confirmation)%> <p><strong><%=h @project_to_destroy.name %></strong><br />
<%=l(:text_project_destroy_confirmation)%></p>
<% if @project_to_destroy.children.any? %>
<br /><%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.children.sort.collect{|p| p.to_s}.join(', ')))) %>
<% end %>
</p>
<p> <p>
<% form_tag({:controller => 'projects', :action => 'destroy', :id => @project_to_destroy}) do %> <% form_tag({:controller => 'projects', :action => 'destroy', :id => @project_to_destroy}) do %>
<label><%= check_box_tag 'confirm', 1 %> <%= l(:general_text_Yes) %></label> <%= hidden_field_tag "confirm", 1 %>
<%= submit_tag l(:button_delete) %> <%= submit_tag l(:button_delete) %>
<% end %> <% end %>
</p> </p>
</center>
</div> </div>
+3 -7
View File
@@ -70,13 +70,10 @@ top = headers_height + 8
@events.each do |i| %> @events.each do |i| %>
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small> <div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
<% if i.is_a? Issue %> <% if i.is_a? Issue %>
<%= h("#{i.project} -") unless @project && @project == i.project %> <%= h("#{i.project.name} -") unless @project && @project == i.project %>
<%= link_to_issue i %>: <%=h i.subject %> <%= link_to_issue i %>: <%=h i.subject %>
<% else %> <% else %>
<span class="icon icon-package"> <%= link_to_version i, :class => "icon icon-package" %>
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i %>
</span>
<% end %> <% end %>
</small></div> </small></div>
<% top = top + 20 <% top = top + 20
@@ -200,8 +197,7 @@ top = headers_height + 10
%> %>
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div> <div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task"> <div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
<%= h("#{i.project} -") unless @project && @project == i.project %> <strong><%= i.name %></strong>
<strong><%=h i %></strong>
</div> </div>
<% end %> <% end %>
<% top = top + 20 <% top = top + 20
+4 -4
View File
@@ -9,10 +9,10 @@
<table class="list"> <table class="list">
<thead><tr> <thead><tr>
<th><%=l(:field_version)%></th> <th><%=l(:field_version)%></th>
<%= sort_header_tag("#{Attachment.table_name}.filename", :caption => l(:field_filename)) %> <th><%=l(:field_filename)%></th>
<%= sort_header_tag("#{Attachment.table_name}.created_on", :caption => l(:label_date), :default_order => 'desc') %> <th><%=l(:label_date)%></th>
<%= sort_header_tag("#{Attachment.table_name}.filesize", :caption => l(:field_filesize), :default_order => 'desc') %> <th><%=l(:field_filesize)%></th>
<%= sort_header_tag("#{Attachment.table_name}.downloads", :caption => l(:label_downloads_abbr), :default_order => 'desc') %> <th><%=l(:label_downloads_abbr)%></th>
<th>MD5</th> <th>MD5</th>
<% if delete_allowed %><th></th><% end %> <% if delete_allowed %><th></th><% end %>
</tr></thead> </tr></thead>
+6 -6
View File
@@ -59,19 +59,19 @@ function toggle_multi_select(field) {
<table width="100%"> <table width="100%">
<tr> <tr>
<td> <td>
<table> <table style="padding:0;">
<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %> <% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %>
<% field = filter[0] <% field = filter[0]
options = filter[1] %> options = filter[1] %>
<tr <%= 'style="display:none;"' unless query.has_filter?(field) %> id="tr_<%= field %>" class="filter"> <tr <%= 'style="display:none;"' unless query.has_filter?(field) %> id="tr_<%= field %>">
<td style="width:200px;"> <td valign="top" style="width:200px;">
<%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %> <%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %>
<label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label> <label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label>
</td> </td>
<td style="width:150px;"> <td valign="top" style="width:150px;">
<%= select_tag "operators[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %> <%= select_tag "operators[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %>
</td> </td>
<td> <td valign="top">
<div id="div_values_<%= field %>" style="display:none;"> <div id="div_values_<%= field %>" style="display:none;">
<% case options[:type] <% case options[:type]
when :list, :list_optional, :list_status, :list_subprojects %> when :list, :list_optional, :list_status, :list_subprojects %>
@@ -93,7 +93,7 @@ function toggle_multi_select(field) {
<% end %> <% end %>
</table> </table>
</td> </td>
<td class="add-filter"> <td align="right" valign="top">
<%= l(:label_filter_add) %>: <%= l(:label_filter_add) %>:
<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/\_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), :onchange => "add_filter();", :class => "select-small" %> <%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/\_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), :onchange => "add_filter();", :class => "select-small" %>
</td> </td>
+3 -8
View File
@@ -6,16 +6,11 @@
<p><label for="query_name"><%=l(:field_name)%></label> <p><label for="query_name"><%=l(:field_name)%></label>
<%= text_field 'query', 'name', :size => 80 %></p> <%= text_field 'query', 'name', :size => 80 %></p>
<% if User.current.admin? || (@project && current_role.allowed_to?(:manage_public_queries)) %> <% if current_role.allowed_to?(:manage_public_queries) %>
<p><label for="query_is_public"><%=l(:field_is_public)%></label> <p><label for="query_is_public"><%=l(:field_is_public)%></label>
<%= check_box 'query', 'is_public', <%= check_box 'query', 'is_public' %></p>
:onchange => (User.current.admin? ? nil : 'if (this.checked) {$("query_is_for_all").checked = false; $("query_is_for_all").disabled = true;} else {$("query_is_for_all").disabled = false;}') %></p>
<% end %> <% end %>
<p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label>
<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?,
:disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p>
<p><label for="query_default_columns"><%=l(:label_default_columns)%></label> <p><label for="query_default_columns"><%=l(:label_default_columns)%></label>
<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', <%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns',
:onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %></p> :onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %></p>
+1 -1
View File
@@ -49,7 +49,7 @@
<td><div class="square action_<%= change.action %>"></div> <%= change.path %> <%= "(#{change.revision})" unless change.revision.blank? %></td> <td><div class="square action_<%= change.action %>"></div> <%= change.path %> <%= "(#{change.revision})" unless change.revision.blank? %></td>
<td align="right"> <td align="right">
<% if change.action == "M" %> <% if change.action == "M" %>
<%= link_to l(:label_view_diff), :action => 'diff', :id => @project, :path => without_leading_slash(change.path), :rev => @changeset.revision %> <%= link_to l(:label_view_diff), :action => 'diff', :id => @project, :path => change.path, :rev => @changeset.revision %>
<% end %> <% end %>
</td> </td>
</tr> </tr>
-28
View File
@@ -1,28 +0,0 @@
<fieldset id="filters"><legend><%= l(:label_date_range) %></legend>
<p>
<%= radio_button_tag 'period_type', '1', !@free_period %>
<%= select_tag 'period', options_for_period_select(params[:period]),
:onchange => 'this.form.onsubmit();',
:onfocus => '$("period_type_1").checked = true;' %>
</p>
<p>
<%= radio_button_tag 'period_type', '2', @free_period %>
<span onclick="$('period_type_2').checked = true;">
<%= l(:label_date_from) %>
<%= text_field_tag 'from', @from, :size => 10 %> <%= calendar_for('from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'to', @to, :size => 10 %> <%= calendar_for('to') %>
</span>
<%= submit_tag l(:button_apply), :name => nil %>
</p>
</fieldset>
<div class="tabs">
<% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %>
<ul>
<li><%= link_to(l(:label_details), url_params.merge({:controller => 'timelog', :action => 'details', :project_id => @project }),
:class => (@controller.action_name == 'details' ? 'selected' : nil)) %></li>
<li><%= link_to(l(:label_report), url_params.merge({:controller => 'timelog', :action => 'report', :project_id => @project}),
:class => (@controller.action_name == 'report' ? 'selected' : nil)) %></li>
</ul>
</div>
+1 -3
View File
@@ -1,6 +1,5 @@
<table class="list time-entries"> <table class="list time-entries">
<thead> <thead>
<tr>
<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %> <%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
<%= sort_header_tag('user_id', :caption => l(:label_member)) %> <%= sort_header_tag('user_id', :caption => l(:label_member)) %>
<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %> <%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
@@ -9,7 +8,6 @@
<th><%= l(:field_comments) %></th> <th><%= l(:field_comments) %></th>
<%= sort_header_tag('hours', :caption => l(:field_hours)) %> <%= sort_header_tag('hours', :caption => l(:field_hours)) %>
<th></th> <th></th>
</tr>
</thead> </thead>
<tbody> <tbody>
<% entries.each do |entry| -%> <% entries.each do |entry| -%>
@@ -37,5 +35,5 @@
</td> </td>
</tr> </tr>
<% end -%> <% end -%>
</tbody> </tbdoy>
</table> </table>
+3 -5
View File
@@ -1,16 +1,14 @@
<% @hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %> <% @hours.collect {|h| h[criterias[level]]}.uniq.each do |value| %>
<% hours_for_value = select_hours(hours, criterias[level], value) -%> <% hours_for_value = select_hours(hours, criterias[level], value) -%>
<% next if hours_for_value.empty? -%> <% next if hours_for_value.empty? -%>
<tr class="<%= cycle('odd', 'even') %> <%= 'last-level' unless criterias.length > level+1 %>"> <tr class="<%= cycle('odd', 'even') %> <%= 'last-level' unless criterias.length > level+1 %>">
<%= '<td></td>' * level %> <%= '<td></td>' * level %>
<td><%= format_criteria_value(criterias[level], value) %></td> <td><%= value.nil? ? l(:label_none) : @available_criterias[criterias[level]][:klass].find_by_id(value) %></td>
<%= '<td></td>' * (criterias.length - level - 1) -%> <%= '<td></td>' * (criterias.length - level - 1) -%>
<% total = 0 -%>
<% @periods.each do |period| -%> <% @periods.each do |period| -%>
<% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)); total += sum -%> <% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) %>
<td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td> <td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td>
<% end -%> <% end -%>
<td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
</tr> </tr>
<% if criterias.length > level+1 -%> <% if criterias.length > level+1 -%>
<%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %> <%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %>
+24 -2
View File
@@ -1,4 +1,5 @@
<div class="contextual"> <div class="contextual">
<%= link_to(l(:label_report), {:controller => 'timelog', :action => 'report', :project_id => @project}, :class => 'icon icon-report') %>
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
</div> </div>
@@ -11,7 +12,23 @@
<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %> <% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %>
<%= hidden_field_tag 'project_id', params[:project_id] %> <%= hidden_field_tag 'project_id', params[:project_id] %>
<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %> <%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>
<%= render :partial => 'date_range' %>
<fieldset><legend><%= l(:label_date_range) %></legend>
<p>
<%= radio_button_tag 'period_type', '1', !@free_period %>
<%= select_tag 'period', options_for_period_select(params[:period]),
:onchange => 'this.form.onsubmit();',
:onfocus => '$("period_type_1").checked = true;' %>
</p>
<p>
<%= radio_button_tag 'period_type', '2', @free_period %>
<%= l(:label_date_from) %>
<%= text_field_tag 'from', @from, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'to', @to, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('to') %>
<%= submit_tag l(:button_apply), :name => nil, :onclick => '$("period_type_2").checked = true;' %>
</p>
</fieldset>
<% end %> <% end %>
<div class="total-hours"> <div class="total-hours">
@@ -28,4 +45,9 @@
</p> </p>
<% end %> <% end %>
<% html_title l(:label_spent_time), l(:label_details) %> <% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+7 -1
View File
@@ -2,7 +2,6 @@
<% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :project_id => @time_entry.project} do |f| %> <% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :project_id => @time_entry.project} do |f| %>
<%= error_messages_for 'time_entry' %> <%= error_messages_for 'time_entry' %>
<%= back_url_hidden_field_tag %>
<div class="box"> <div class="box">
<p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p> <p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p>
@@ -15,3 +14,10 @@
<%= submit_tag l(:button_save) %> <%= submit_tag l(:button_save) %>
<% end %> <% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+30 -30
View File
@@ -1,31 +1,35 @@
<div class="contextual"> <div class="contextual">
<%= link_to(l(:label_details), {:controller => 'timelog', :action => 'details', :project_id => @project}, :class => 'icon icon-details') %>
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
</div> </div>
<h2><%= l(:label_spent_time) %></h2> <h2><%= l(:label_spent_time) %></h2>
<% form_remote_tag(:url => {}, :update => 'content') do %> <% form_remote_tag(:url => {:project_id => @project}, :update => 'content') do %>
<% @criterias.each do |criteria| %> <% @criterias.each do |criteria| %>
<%= hidden_field_tag 'criterias[]', criteria, :id => nil %> <%= hidden_field_tag 'criterias[]', criteria %>
<% end %> <% end %>
<%= hidden_field_tag 'project_id', params[:project_id] %> <fieldset><legend><%= l(:label_date_range) %></legend>
<%= render :partial => 'date_range' %> <p>
<%= l(:label_date_from) %>
<%= text_field_tag 'date_from', @date_from, :size => 10 %><%= calendar_for('date_from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'date_to', @date_to, :size => 10 %><%= calendar_for('date_to') %>
<%= l(:label_details) %>
<%= select_tag 'period', options_for_select([[l(:label_year), 'year'],
[l(:label_month), 'month'],
[l(:label_week), 'week']], @columns) %>
&nbsp;
<%= submit_tag l(:button_apply) %>
</p>
</fieldset>
<p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], <p><%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
[l(:label_month), 'month'],
[l(:label_week), 'week'],
[l(:label_day_plural).titleize, 'day']], @columns),
:onchange => "this.form.onsubmit();" %>
<%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
:onchange => "this.form.onsubmit();", :onchange => "this.form.onsubmit();",
:style => 'width: 200px', :style => 'width: 200px',
:id => nil,
:disabled => (@criterias.length >= 3)) %> :disabled => (@criterias.length >= 3)) %>
<%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :date_from => @date_from, :date_to => @date_to, :period => @columns}, :update => 'content'},
:update => 'content' :class => 'icon icon-reload' %></p>
}, :class => 'icon icon-reload' %></p>
<% end %>
<% unless @criterias.empty? %> <% unless @criterias.empty? %>
<div class="total-hours"> <div class="total-hours">
@@ -37,13 +41,11 @@
<thead> <thead>
<tr> <tr>
<% @criterias.each do |criteria| %> <% @criterias.each do |criteria| %>
<th><%= l(@available_criterias[criteria][:label]) %></th> <th width="15%"><%= l(@available_criterias[criteria][:label]) %></th>
<% end %> <% end %>
<% columns_width = (40 / (@periods.length+1)).to_i %>
<% @periods.each do |period| %> <% @periods.each do |period| %>
<th class="period" width="<%= columns_width %>%"><%= period %></th> <th width="<%= ((100 - @criterias.length * 15 - 15 ) / @periods.length).to_i %>%"><%= period %></th>
<% end %> <% end %>
<th class="total" width="<%= columns_width %>%"><%= l(:label_total) %></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -51,22 +53,20 @@
<tr class="total"> <tr class="total">
<td><%= l(:label_total) %></td> <td><%= l(:label_total) %></td>
<%= '<td></td>' * (@criterias.size - 1) %> <%= '<td></td>' * (@criterias.size - 1) %>
<% total = 0 -%>
<% @periods.each do |period| -%> <% @periods.each do |period| -%>
<% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%> <% sum = sum_hours(select_hours(@hours, @columns, period.to_s)) %>
<td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td> <td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td>
<% end -%> <% end -%>
<td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<% end %>
<p class="other-formats">
<%= l(:label_export_to) %>
<span><%= link_to 'CSV', params.merge({:format => 'csv'}), :class => 'csv' %></span>
</p>
<% end %> <% end %>
<% end %> <% end %>
<% html_title l(:label_spent_time), l(:label_report) %> <% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+7
View File
@@ -30,3 +30,10 @@
</div> </div>
</div> </div>
<!--[eoform:user]--> <!--[eoform:user]-->
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
+11 -1
View File
@@ -33,7 +33,17 @@
<td align="center"><%= image_tag('true.png') if user.admin? %></td> <td align="center"><%= image_tag('true.png') if user.admin? %></td>
<td class="created_on" align="center"><%= format_time(user.created_on) %></td> <td class="created_on" align="center"><%= format_time(user.created_on) %></td>
<td class="last_login_on" align="center"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td> <td class="last_login_on" align="center"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td>
<td><small><%= change_status_link(user) %></small></td> <td>
<small>
<% if user.locked? -%>
<%= link_to l(:button_unlock), {:action => 'edit', :id => user, :user => {:status => User::STATUS_ACTIVE}}, :method => :post, :class => 'icon icon-unlock' %>
<% elsif user.registered? -%>
<%= link_to l(:button_activate), {:action => 'edit', :id => user, :user => {:status => User::STATUS_ACTIVE}}, :method => :post, :class => 'icon icon-unlock' %>
<% else -%>
<%= link_to l(:button_lock), {:action => 'edit', :id => user, :user => {:status => User::STATUS_LOCKED}}, :method => :post, :class => 'icon icon-lock' %>
<% end -%>
</small>
</td>
</tr> </tr>
<% end -%> <% end -%>
</tbody> </tbody>
+7
View File
@@ -6,3 +6,10 @@
<p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p> <p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
<p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p> <p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
</div> </div>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
-3
View File
@@ -4,9 +4,6 @@
# you don't control web/app server and can't set it the proper way # you don't control web/app server and can't set it the proper way
# ENV['RAILS_ENV'] ||= 'production' # ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION
# Bootstrap the Rails environment, frameworks, and default configuration # Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot') require File.join(File.dirname(__FILE__), 'boot')
-32
View File
@@ -5,38 +5,6 @@ Copyright (C) 2006-2008 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2008-04-28 v0.7.0
* Forces Redmine to use rails 2.0.2 gem when vendor/rails is not present
* Queries can be marked as 'For all projects'. Such queries will be available on all projects and on the global issue list.
* Add predefined date ranges to the time report
* Time report can be done at issue level
* Various timelog report enhancements
* Accept the following formats for "hours" field: 1h, 1 h, 1 hour, 2 hours, 30m, 30min, 1h30, 1h30m, 1:30
* Display the context menu above and/or to the left of the click if needed
* Make the admin project files list sortable
* Mercurial: display working directory files sizes unless browsing a specific revision
* Preserve status filter and page number when using lock/unlock/activate links on the users list
* Redmine.pm support for LDAP authentication
* Better error message and AR errors in log for failed LDAP on-the-fly user creation
* Redirected user to where he is coming from after logging hours
* Warn user that subprojects are also deleted when deleting a project
* Include subprojects versions on calendar and gantt
* Notify project members when a message is posted if they want to receive notifications
* Fixed: Feed content limit setting has no effect
* Fixed: Priorities not ordered when displayed as a filter in issue list
* Fixed: can not display attached images inline in message replies
* Fixed: Boards are not deleted when project is deleted
* Fixed: trying to preview a new issue raises an exception with postgresql
* Fixed: single file 'View difference' links do not work because of duplicate slashes in url
* Fixed: inline image not displayed when including a wiki page
* Fixed: CVS duplicate key violation
* Fixed: ActiveRecord::StaleObjectError exception on closing a set of circular duplicate issues
* Fixed: custom field filters behaviour
* Fixed: Postgresql 8.3 compatibility
* Fixed: Links to repository directories don't work
== 2008-03-29 v0.7.0-rc1 == 2008-03-29 v0.7.0-rc1
* Overall activity view and feed added, link is available on the project list * Overall activity view and feed added, link is available on the project list
+7 -34
View File
@@ -8,8 +8,8 @@ against redmine database
=head1 SYNOPSIS =head1 SYNOPSIS
This module allow anonymous users to browse public project and This module allow anonymous users to browse public project and
registred users to browse and commit their project. Authentication is registred users to browse and commit their project. authentication is
done against the redmine database or the LDAP configured in redmine. done on the redmine database.
This method is far simpler than the one with pam_* and works with all This method is far simpler than the one with pam_* and works with all
database without an hassle but you need to have apache/mod_perl on the database without an hassle but you need to have apache/mod_perl on the
@@ -29,11 +29,6 @@ On debian/ubuntu you must do :
aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
If your Redmine users use LDAP authentication, you will also need
Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
=head1 CONFIGURATION =head1 CONFIGURATION
## if the module isn't in your perl path ## if the module isn't in your perl path
@@ -95,8 +90,6 @@ use strict;
use DBI; use DBI;
use Digest::SHA1; use Digest::SHA1;
# optional module for LDAP authentication
my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
use Apache2::Module; use Apache2::Module;
use Apache2::Access; use Apache2::Access;
@@ -147,7 +140,7 @@ sub is_public_project {
my $dbh = connect_database($r); my $dbh = connect_database($r);
my $sth = $dbh->prepare( my $sth = $dbh->prepare(
"SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;" "SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
); );
$sth->execute($project_id); $sth->execute($project_id);
@@ -183,37 +176,17 @@ sub is_member {
my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
my $sth = $dbh->prepare( my $sth = $dbh->prepare(
"SELECT hashed_password, auth_source_id FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;" "SELECT hashed_password FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;"
); );
$sth->execute($redmine_user, $project_id); $sth->execute($redmine_user, $project_id);
my $ret; my $ret;
while (my @row = $sth->fetchrow_array) { while (my @row = $sth->fetchrow_array) {
unless ($row[1]) { if ($row[0] eq $pass_digest) {
if ($row[0] eq $pass_digest) { $ret = 1;
$ret = 1; last;
last;
}
} elsif ($CanUseLDAPAuth) {
my $sthldap = $dbh->prepare(
"SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
);
$sthldap->execute($row[1]);
while (my @rowldap = $sthldap->fetchrow_array) {
my $ldap = Authen::Simple::LDAP->new(
host => ($rowldap[2] == 1 || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]" : $rowldap[0],
port => $rowldap[1],
basedn => $rowldap[5],
binddn => $rowldap[3] ? $rowldap[3] : "",
bindpw => $rowldap[4] ? $rowldap[4] : "",
filter => "(".$rowldap[6]."=%s)"
);
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
}
$sthldap->finish();
} }
} }
$sth->finish();
$dbh->disconnect(); $dbh->disconnect();
$ret; $ret;
+82 -83
View File
@@ -48,8 +48,8 @@ general_text_no: 'не'
general_text_yes: 'да' general_text_yes: 'да'
general_lang_name: 'Bulgarian' general_lang_name: 'Bulgarian'
general_csv_separator: ',' general_csv_separator: ','
general_csv_encoding: UTF-8 general_csv_encoding: cp1251
general_pdf_encoding: UTF-8 general_pdf_encoding: cp1251
general_day_names: Понеделник,Вторник,Сряда,Четвъртък,Петък,Събота,Неделя general_day_names: Понеделник,Вторник,Сряда,Четвъртък,Петък,Събота,Неделя
general_first_day_of_week: '1' general_first_day_of_week: '1'
@@ -57,11 +57,11 @@ notice_account_updated: Профилът е обновен успешно.
notice_account_invalid_creditentials: Невалиден потребител или парола. notice_account_invalid_creditentials: Невалиден потребител или парола.
notice_account_password_updated: Паролата е успешно променена. notice_account_password_updated: Паролата е успешно променена.
notice_account_wrong_password: Грешна парола notice_account_wrong_password: Грешна парола
notice_account_register_done: Профилът е създаден успешно. notice_account_register_done: Акаунтът е създаден успешно.
notice_account_unknown_email: Непознат e-mail. notice_account_unknown_email: Непознат потребител.
notice_can_t_change_password: Този профил е с външен метод за оторизация. Невъзможна смяна на паролата. notice_can_t_change_password: Този акаунт е с външен метод за оторизация. Невъзможна смяна на паролата.
notice_account_lost_email_sent: Изпратен ви е e-mail с инструкции за избор на нова парола. notice_account_lost_email_sent: Изпратен ви е e-mail с инструкции за избор на нова парола.
notice_account_activated: Профилът ви е активиран. Вече може да влезете в системата. notice_account_activated: Акаунтът ви е активиран. Вече може да влезете.
notice_successful_create: Успешно създаване. notice_successful_create: Успешно създаване.
notice_successful_update: Успешно обновяване. notice_successful_update: Успешно обновяване.
notice_successful_delete: Успешно изтриване. notice_successful_delete: Успешно изтриване.
@@ -78,8 +78,8 @@ error_scm_command_failed: "Грешка при опит за комуникац
mail_subject_lost_password: Вашата парола (%s) mail_subject_lost_password: Вашата парола (%s)
mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:' mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:'
mail_subject_register: Активация на профил (%s) mail_subject_register: Активация на акаунт (%s)
mail_body_register: 'За да активирате профила си използвайте следния линк:' mail_body_register: 'За да активирате акаунта си използвайте следния линк:'
gui_validation_error: 1 грешка gui_validation_error: 1 грешка
gui_validation_error_plural: %d грешки gui_validation_error_plural: %d грешки
@@ -113,11 +113,11 @@ field_notes: Бележка
field_is_closed: Затворена задача field_is_closed: Затворена задача
field_is_default: Статус по подразбиране field_is_default: Статус по подразбиране
field_tracker: Тракер field_tracker: Тракер
field_subject: Относно field_subject: Тема
field_due_date: Крайна дата field_due_date: Крайна дата
field_assigned_to: Възложена на field_assigned_to: Възложена на
field_priority: Приоритет field_priority: Приоритет
field_fixed_version: Планувана версия field_fixed_version: Target version
field_user: Потребител field_user: Потребител
field_role: Роля field_role: Роля
field_homepage: Начална страница field_homepage: Начална страница
@@ -138,7 +138,7 @@ field_version: Версия
field_type: Тип field_type: Тип
field_host: Хост field_host: Хост
field_port: Порт field_port: Порт
field_account: Профил field_account: Акаунт
field_base_dn: Base DN field_base_dn: Base DN
field_attr_login: Login attribute field_attr_login: Login attribute
field_attr_firstname: Firstname attribute field_attr_firstname: Firstname attribute
@@ -163,7 +163,7 @@ field_delay: Отместване
field_assignable: Възможно е възлагане на задачи за тази роля field_assignable: Възможно е възлагане на задачи за тази роля
field_redirect_existing_links: Пренасочване на съществуващи линкове field_redirect_existing_links: Пренасочване на съществуващи линкове
field_estimated_hours: Изчислено време field_estimated_hours: Изчислено време
field_default_value: Стойност по подразбиране field_default_value: Статус по подразбиране
setting_app_title: Заглавие setting_app_title: Заглавие
setting_app_subtitle: Описание setting_app_subtitle: Описание
@@ -171,15 +171,15 @@ setting_welcome_text: Допълнителен текст
setting_default_language: Език по подразбиране setting_default_language: Език по подразбиране
setting_login_required: Изискване за вход в системата setting_login_required: Изискване за вход в системата
setting_self_registration: Регистрация от потребители setting_self_registration: Регистрация от потребители
setting_attachment_max_size: Максимална големина на прикачен файл setting_attachment_max_size: Максимално голям приложен файл
setting_issues_export_limit: Лимит за експорт на задачи setting_issues_export_limit: Лимит за експорт на задачи
setting_mail_from: E-mail адрес за емисии setting_mail_from: E-mail адрес за емисии
setting_host_name: Хост setting_host_name: Хост
setting_text_formatting: Форматиране на текста setting_text_formatting: Форматиране на текста
setting_wiki_compression: Wiki компресиране на историята setting_wiki_compression: Wiki компресиране на историята
setting_feeds_limit: Лимит на Feeds setting_feeds_limit: Лимит на Feeds
setting_autofetch_changesets: Автоматично обработване на ревизиите setting_autofetch_changesets: Автоматично обработване на commits в хранилището
setting_sys_api_enabled: Разрешаване на WS за управление setting_sys_api_enabled: Разрешаване на WS за управление на хранилището
setting_commit_ref_keywords: Отбелязващи ключови думи setting_commit_ref_keywords: Отбелязващи ключови думи
setting_commit_fix_keywords: Приключващи ключови думи setting_commit_fix_keywords: Приключващи ключови думи
setting_autologin: Автоматичен вход setting_autologin: Автоматичен вход
@@ -231,7 +231,7 @@ label_password_lost: Забравена парола
label_home: Начало label_home: Начало
label_my_page: Лична страница label_my_page: Лична страница
label_my_account: Профил label_my_account: Профил
label_my_projects: Проекти, в които участвам label_my_projects: Моите проекти
label_administration: Администрация label_administration: Администрация
label_login: Вход label_login: Вход
label_logout: Изход label_logout: Изход
@@ -375,8 +375,8 @@ label_f_hour_plural: %.2f часа
label_time_tracking: Отделяне на време label_time_tracking: Отделяне на време
label_change_plural: Промени label_change_plural: Промени
label_statistics: Статистики label_statistics: Статистики
label_commits_per_month: Ревизии по месеци label_commits_per_month: Commits за месец
label_commits_per_author: Ревизии по автор label_commits_per_author: Commits за автор
label_view_diff: Виж разликите label_view_diff: Виж разликите
label_diff_inline: хоризонтално label_diff_inline: хоризонтално
label_diff_side_by_side: вертикално label_diff_side_by_side: вертикално
@@ -389,7 +389,7 @@ label_applied_status: Промени статуса на
label_loading: Зареждане... label_loading: Зареждане...
label_relation_new: Нова релация label_relation_new: Нова релация
label_relation_delete: Изтриване на релация label_relation_delete: Изтриване на релация
label_relates_to: свързана със label_relates_to: Свързана със
label_duplicates: дублира label_duplicates: дублира
label_blocks: блокира label_blocks: блокира
label_blocked_by: блокирана от label_blocked_by: блокирана от
@@ -427,10 +427,10 @@ label_updated_time: Обновена преди %s
label_jump_to_a_project: Проект... label_jump_to_a_project: Проект...
button_login: Вход button_login: Вход
button_submit: Прикачване button_submit: Приложи
button_save: Запис button_save: Запис
button_check_all: Избор на всички button_check_all: Маркирай всички
button_uncheck_all: Изчистване на всички button_uncheck_all: Изчисти всички
button_delete: Изтриване button_delete: Изтриване
button_create: Създаване button_create: Създаване
button_test: Тест button_test: Тест
@@ -481,9 +481,9 @@ text_length_between: От %d до %d символа.
text_tracker_no_workflow: Няма дефиниран работен процес за този тракер text_tracker_no_workflow: Няма дефиниран работен процес за този тракер
text_unallowed_characters: Непозволени символи text_unallowed_characters: Непозволени символи
text_comma_separated: Позволено е изброяване (с разделител запетая). text_comma_separated: Позволено е изброяване (с разделител запетая).
text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от ревизии text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от commit съобщения
text_issue_added: Публикувана е нова задача с номер %s (от %s). text_issue_added: Публикувана е нова задача с номер %s (by %s).
text_issue_updated: Задача %s е обновена (от %s). text_issue_updated: Задача %s е обновена (by %s).
text_wiki_destroy_confirmation: Сигурни ли сте, че искате да изтриете това Wiki и цялото му съдържание? text_wiki_destroy_confirmation: Сигурни ли сте, че искате да изтриете това Wiki и цялото му съдържание?
text_issue_category_destroy_question: Има задачи (%d) обвързани с тази категория. Какво ще изберете? text_issue_category_destroy_question: Има задачи (%d) обвързани с тази категория. Какво ще изберете?
text_issue_category_destroy_assignments: Премахване на връзките с категорията text_issue_category_destroy_assignments: Премахване на връзките с категорията
@@ -515,11 +515,11 @@ enumeration_issue_priorities: Приоритети на задачи
enumeration_doc_categories: Категории документи enumeration_doc_categories: Категории документи
enumeration_activities: Дейности (time tracking) enumeration_activities: Дейности (time tracking)
label_file_plural: Файлове label_file_plural: Файлове
label_changeset_plural: Ревизии label_changeset_plural: Changesets
field_column_names: Колони field_column_names: Колони
label_default_columns: По подразбиране label_default_columns: По подразбиране
setting_issue_list_default_columns: Показвани колони по подразбиране setting_issue_list_default_columns: Показвани колони по подразбиране
setting_repositories_encodings: Кодови таблици setting_repositories_encodings: Кодови таблици на хранилищата
notice_no_issue_selected: "Няма избрани задачи." notice_no_issue_selected: "Няма избрани задачи."
label_bulk_edit_selected_issues: Редактиране на задачи label_bulk_edit_selected_issues: Редактиране на задачи
label_no_change_option: (Без промяна) label_no_change_option: (Без промяна)
@@ -536,20 +536,20 @@ label_user_mail_option_none: "Само за наблюдавани или в к
setting_emails_footer: Подтекст за e-mail setting_emails_footer: Подтекст за e-mail
label_float: Дробно label_float: Дробно
button_copy: Копиране button_copy: Копиране
mail_body_account_information_external: Можете да използвате вашия "%s" профил за вход. mail_body_account_information_external: Можете да използвате вашия "%s" акаунт за вход.
mail_body_account_information: Информацията за профила ви mail_body_account_information: Информацията за акаунта
setting_protocol: Протокол setting_protocol: Протокол
label_user_mail_no_self_notified: "Не искам известия за извършени от мен промени" label_user_mail_no_self_notified: "Не искам известия за извършени от мен промени"
setting_time_format: Формат на часа setting_time_format: Формат на часа
label_registration_activation_by_email: активиране на профила по email label_registration_activation_by_email: активиране на акаунта по email
mail_subject_account_activation_request: Заявка за активиране на профил в %s mail_subject_account_activation_request: Заявка за активиране на акаунт в %s
mail_body_account_activation_request: 'Има новорегистриран потребител (%s), очакващ вашето одобрение:' mail_body_account_activation_request: 'Има новорегистриран потребител (%s), очакващ вашето одобрение:'
label_registration_automatic_activation: автоматично активиране label_registration_automatic_activation: автоматично активиране
label_registration_manual_activation: ръчно активиране label_registration_manual_activation: ръчно активиране
notice_account_pending: "Профилът Ви е създаден и очаква одобрение от администратор." notice_account_pending: "Акаунтът Ви е създаден и очаква одобрение от администратор."
field_time_zone: Часова зона field_time_zone: Часова зона
text_caracters_minimum: Минимум %d символа. text_caracters_minimum: Минимум %d символа.
setting_bcc_recipients: Получатели на скрито копие (bcc) setting_bcc_recipients: Blind carbon copy (bcc) получатели
button_annotate: Анотация button_annotate: Анотация
label_issues_by: Задачи по %s label_issues_by: Задачи по %s
field_searchable: С възможност за търсене field_searchable: С възможност за търсене
@@ -566,55 +566,54 @@ label_general: Основни
label_repository_plural: Хранилища label_repository_plural: Хранилища
label_associated_revisions: Асоциирани ревизии label_associated_revisions: Асоциирани ревизии
setting_user_format: Потребителски формат setting_user_format: Потребителски формат
text_status_changed_by_changeset: Приложено с ревизия %s. text_status_changed_by_changeset: Applied in changeset %s.
label_more: Още label_more: More
text_issues_destroy_confirmation: 'Сигурни ли сте, че искате да изтриете избраните задачи?' text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_scm: SCM (Система за контрол на кода) label_scm: SCM
text_select_project_modules: 'Изберете активните модули за този проект:' text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: Добавена задача label_issue_added: Issue added
label_issue_updated: Обновена задача label_issue_updated: Issue updated
label_document_added: Добавен документ label_document_added: Document added
label_message_posted: Добавено съобщение label_message_posted: Message added
label_file_added: Добавен файл label_file_added: File added
label_news_added: Добавена новина label_news_added: News added
project_module_boards: Форуми project_module_boards: Boards
project_module_issue_tracking: Тракинг project_module_issue_tracking: Issue tracking
project_module_wiki: Wiki project_module_wiki: Wiki
project_module_files: Файлове project_module_files: Files
project_module_documents: Документи project_module_documents: Documents
project_module_repository: Хранилище project_module_repository: Repository
project_module_news: Новини project_module_news: News
project_module_time_tracking: Отделяне на време project_module_time_tracking: Time tracking
text_file_repository_writable: Възможност за писане в хранилището с файлове text_file_repository_writable: File repository writable
text_default_administrator_account_changed: Сменен фабричния администраторски профил text_default_administrator_account_changed: Default administrator account changed
text_rmagick_available: Наличен RMagick (по избор) text_rmagick_available: RMagick available (optional)
button_configure: Конфигуриране button_configure: Configure
label_plugins: Плъгини label_plugins: Plugins
label_ldap_authentication: LDAP оторизация label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_this_month: текущия месец label_this_month: this month
label_last_n_days: последните %d дни label_last_n_days: last %d days
label_all_time: всички label_all_time: all time
label_this_year: текущата година label_this_year: this year
label_date_range: Период label_date_range: Date range
label_last_week: последната седмица label_last_week: last week
label_yesterday: вчера label_yesterday: yesterday
label_last_month: последния месец label_last_month: last month
label_add_another_file: Добавяне на друг файл label_add_another_file: Add another file
label_optional_description: Незадължително описание label_optional_description: Optional description
text_destroy_time_entries_question: %.02f часа са отделени на задачите, които искате да изтриете. Какво избирате? text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ?
error_issue_not_found_in_project: 'Задачата не е намерена или не принадлежи на този проект' error_issue_not_found_in_project: 'The issue was not found or does not belong to this project'
text_assign_time_entries_to_project: Прехвърляне на отделеното време към проект text_assign_time_entries_to_project: Assign reported hours to the project
text_destroy_time_entries: Изтриване на отделеното време text_destroy_time_entries: Delete reported hours
text_reassign_time_entries: 'Прехвърляне на отделеното време към задача:' text_reassign_time_entries: 'Reassign reported hours to this issue:'
setting_activity_days_default: Брой дни показвани на таб Дейност setting_activity_days_default: Days displayed on project activity
label_chronological_order: Хронологичен ред label_chronological_order: In chronological order
field_comments_sorting: Сортиране на коментарите field_comments_sorting: Display comments
label_reverse_chronological_order: Обратен хронологичен ред label_reverse_chronological_order: In reverse chronological order
label_preferences: Предпочитания label_preferences: Preferences
setting_display_subprojects_issues: Показване на подпроектите в проектите по подразбиране setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Цялостна дейност label_overall_activity: Overall activity
setting_default_projects_public: Новите проекти са публични по подразбиране setting_default_projects_public: New projects are public by default
error_scm_annotate: "Обектът не съществува или не може да бъде анотиран." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Планиране label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+17 -18
View File
@@ -10,16 +10,16 @@ actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix: actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 den actionview_datehelper_time_in_words_day: 1 den
actionview_datehelper_time_in_words_day_plural: %d dny actionview_datehelper_time_in_words_day_plural: %d dny
actionview_datehelper_time_in_words_hour_about: asi hodinou actionview_datehelper_time_in_words_hour_about: asi hodinu
actionview_datehelper_time_in_words_hour_about_plural: asi %d hodinami actionview_datehelper_time_in_words_hour_about_plural: asi %d hodin
actionview_datehelper_time_in_words_hour_about_single: asi hodinou actionview_datehelper_time_in_words_hour_about_single: asi hodinu
actionview_datehelper_time_in_words_minute: 1 minutou actionview_datehelper_time_in_words_minute: 1 minuta
actionview_datehelper_time_in_words_minute_half: půl minutou actionview_datehelper_time_in_words_minute_half: půl minuty
actionview_datehelper_time_in_words_minute_less_than: méně než minutou actionview_datehelper_time_in_words_minute_less_than: méně než minutu
actionview_datehelper_time_in_words_minute_plural: %d minutami actionview_datehelper_time_in_words_minute_plural: %d minut
actionview_datehelper_time_in_words_minute_single: 1 minutou actionview_datehelper_time_in_words_minute_single: 1 minuta
actionview_datehelper_time_in_words_second_less_than: méně než sekundou actionview_datehelper_time_in_words_second_less_than: méně než sekunda
actionview_datehelper_time_in_words_second_less_than_plural: méně než %d sekundami actionview_datehelper_time_in_words_second_less_than_plural: méně než %d sekund
actionview_instancetag_blank_option: Prosím vyberte actionview_instancetag_blank_option: Prosím vyberte
activerecord_error_inclusion: není zahrnuto v seznamu activerecord_error_inclusion: není zahrnuto v seznamu
@@ -98,7 +98,7 @@ mail_body_account_activation_request: Byl zaregistrován nový uživatel "%s". A
gui_validation_error: 1 chyba gui_validation_error: 1 chyba
gui_validation_error_plural: %d chyb(y) gui_validation_error_plural: %d chyb(y)
field_name: Název field_name: Jméno
field_description: Popis field_description: Popis
field_summary: Přehled field_summary: Přehled
field_is_required: Povinné pole field_is_required: Povinné pole
@@ -306,7 +306,7 @@ label_attribute: Atribut
label_attribute_plural: Atributy label_attribute_plural: Atributy
label_download: %d Download label_download: %d Download
label_download_plural: %d Downloads label_download_plural: %d Downloads
label_no_data: Žádné položky label_no_data: Žádná data k zobrazení
label_change_status: Změnit stav label_change_status: Změnit stav
label_history: Historie label_history: Historie
label_attachment: Soubor label_attachment: Soubor
@@ -480,8 +480,8 @@ label_sort_by: Seřadit podle %s
label_send_test_email: Poslat testovací email label_send_test_email: Poslat testovací email
label_feeds_access_key_created_on: Přístupový klíč pro RSS byl vytvořen před %s label_feeds_access_key_created_on: Přístupový klíč pro RSS byl vytvořen před %s
label_module_plural: Moduly label_module_plural: Moduly
label_added_time_by: 'Přidáno uživatelem %s před %s' label_added_time_by: 'Přidáno před: %s %s'
label_updated_time: 'Aktualizováno před %s' label_updated_time: 'Aktualizováno před: %s'
label_jump_to_a_project: Zvolit projekt... label_jump_to_a_project: Zvolit projekt...
label_file_plural: Soubory label_file_plural: Soubory
label_changeset_plural: Changesety label_changeset_plural: Changesety
@@ -586,7 +586,7 @@ text_no_configuration_data: "Role, fronty, stavy úkolů ani workflow nebyly zat
text_load_default_configuration: Nahrát výchozí konfiguraci text_load_default_configuration: Nahrát výchozí konfiguraci
text_status_changed_by_changeset: Použito v changesetu %s. text_status_changed_by_changeset: Použito v changesetu %s.
text_issues_destroy_confirmation: 'Opravdu si přejete odstranit všechny zvolené úkoly?' text_issues_destroy_confirmation: 'Opravdu si přejete odstranit všechny zvolené úkoly?'
text_select_project_modules: 'Aktivní moduly v tomto projektu:' text_select_project_modules: 'Zvolte moduly aktivní v tomto projektu:'
text_default_administrator_account_changed: Výchozí nastavení administrátorského účtu změněno text_default_administrator_account_changed: Výchozí nastavení administrátorského účtu změněno
text_file_repository_writable: Povolen zápis do repository text_file_repository_writable: Povolen zápis do repository
text_rmagick_available: RMagick k dispozici (volitelné) text_rmagick_available: RMagick k dispozici (volitelné)
@@ -620,6 +620,5 @@ default_activity_development: Vývoj
enumeration_issue_priorities: Priority úkolů enumeration_issue_priorities: Priority úkolů
enumeration_doc_categories: Kategorie dokumentů enumeration_doc_categories: Kategorie dokumentů
enumeration_activities: Aktivity (sledování času) enumeration_activities: Aktivity (sledování času)
error_scm_annotate: "Položka neexistuje nebo nemůže být komentována." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Plánování label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -619,4 +619,3 @@ label_overall_activity: Overordnet aktivitet
setting_default_projects_public: Nye projekter er offentlige som default setting_default_projects_public: Nye projekter er offentlige som default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planlægning label_planning: Planlægning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+22 -23
View File
@@ -71,7 +71,7 @@ notice_locking_conflict: Datum wurde von einem anderen Benutzer geändert.
notice_not_authorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen. notice_not_authorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen.
notice_email_sent: Eine E-Mail wurde an %s gesendet. notice_email_sent: Eine E-Mail wurde an %s gesendet.
notice_email_error: Beim Senden einer E-Mail ist ein Fehler aufgetreten (%s). notice_email_error: Beim Senden einer E-Mail ist ein Fehler aufgetreten (%s).
notice_feeds_access_key_reseted: Ihr Atom-Zugriffsschlüssel wurde zurückgesetzt. notice_feeds_access_key_reseted: Ihr RSS-Zugriffsschlüssel wurde zurückgesetzt.
notice_failed_to_save_issues: "%d von %d ausgewählten Tickets konnte(n) nicht gespeichert werden: %s." notice_failed_to_save_issues: "%d von %d ausgewählten Tickets konnte(n) nicht gespeichert werden: %s."
notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten." notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten."
notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators." notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators."
@@ -80,7 +80,6 @@ notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen
error_can_t_load_default_data: "Die Standard-Konfiguration konnte nicht geladen werden: %s" error_can_t_load_default_data: "Die Standard-Konfiguration konnte nicht geladen werden: %s"
error_scm_not_found: Eintrag und/oder Revision besteht nicht im Projektarchiv. error_scm_not_found: Eintrag und/oder Revision besteht nicht im Projektarchiv.
error_scm_command_failed: "Beim Zugriff auf das Projektarchiv ist ein Fehler aufgetreten: %s" error_scm_command_failed: "Beim Zugriff auf das Projektarchiv ist ein Fehler aufgetreten: %s"
error_scm_annotate: "Der Eintrag existiert nicht oder kann nicht annotiert werden."
error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.' error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.'
mail_subject_lost_password: Ihr %s Kennwort mail_subject_lost_password: Ihr %s Kennwort
@@ -121,8 +120,8 @@ field_project: Projekt
field_issue: Ticket field_issue: Ticket
field_status: Status field_status: Status
field_notes: Kommentare field_notes: Kommentare
field_is_closed: Ticket geschlossen field_is_closed: Problem erledigt
field_is_default: Standardeinstellung field_is_default: Default
field_tracker: Tracker field_tracker: Tracker
field_subject: Thema field_subject: Thema
field_due_date: Abgabedatum field_due_date: Abgabedatum
@@ -134,8 +133,8 @@ field_role: Rolle
field_homepage: Projekt-Homepage field_homepage: Projekt-Homepage
field_is_public: Öffentlich field_is_public: Öffentlich
field_parent: Unterprojekt von field_parent: Unterprojekt von
field_is_in_chlog: Im Change-Log anzeigen field_is_in_chlog: Ansicht im Change-Log
field_is_in_roadmap: In der Roadmap anzeigen field_is_in_roadmap: Ansicht in der Roadmap
field_login: Mitgliedsname field_login: Mitgliedsname
field_mail_notification: Mailbenachrichtigung field_mail_notification: Mailbenachrichtigung
field_admin: Administrator field_admin: Administrator
@@ -178,7 +177,6 @@ field_column_names: Spalten
field_time_zone: Zeitzone field_time_zone: Zeitzone
field_searchable: Durchsuchbar field_searchable: Durchsuchbar
field_default_value: Standardwert field_default_value: Standardwert
field_comments_sorting: Kommentare anzeigen
setting_app_title: Applikations-Titel setting_app_title: Applikations-Titel
setting_app_subtitle: Applikations-Untertitel setting_app_subtitle: Applikations-Untertitel
@@ -193,8 +191,7 @@ setting_bcc_recipients: E-Mails als Blindkopie (BCC) senden
setting_host_name: Hostname setting_host_name: Hostname
setting_text_formatting: Textformatierung setting_text_formatting: Textformatierung
setting_wiki_compression: Wiki-Historie komprimieren setting_wiki_compression: Wiki-Historie komprimieren
setting_feeds_limit: Max. Anzahl Einträge pro Atom-Feed setting_feeds_limit: Feed-Inhalt begrenzen
setting_default_projects_public: Neue Projekte sind standardmäßig öffentlich
setting_autofetch_changesets: Changesets automatisch abrufen setting_autofetch_changesets: Changesets automatisch abrufen
setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen
setting_commit_ref_keywords: Schlüsselwörter (Beziehungen) setting_commit_ref_keywords: Schlüsselwörter (Beziehungen)
@@ -209,8 +206,6 @@ setting_emails_footer: E-Mail-Fußzeile
setting_protocol: Protokoll setting_protocol: Protokoll
setting_per_page_options: Objekte pro Seite setting_per_page_options: Objekte pro Seite
setting_user_format: Benutzer-Anzeigeformat setting_user_format: Benutzer-Anzeigeformat
setting_activity_days_default: Anzahl Tage pro Seite der Projekt-Aktivität
setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen
project_module_issue_tracking: Ticket-Verfolgung project_module_issue_tracking: Ticket-Verfolgung
project_module_time_tracking: Zeiterfassung project_module_time_tracking: Zeiterfassung
@@ -232,7 +227,7 @@ label_project_latest: Neueste Projekte
label_issue: Ticket label_issue: Ticket
label_issue_new: Neues Ticket label_issue_new: Neues Ticket
label_issue_plural: Tickets label_issue_plural: Tickets
label_issue_view_all: Alle Tickets anzeigen label_issue_view_all: Alle Tickets ansehen
label_issues_by: Tickets von %s label_issues_by: Tickets von %s
label_issue_added: Ticket hinzugefügt label_issue_added: Ticket hinzugefügt
label_issue_updated: Ticket aktualisiert label_issue_updated: Ticket aktualisiert
@@ -282,7 +277,6 @@ label_last_updates: zuletzt aktualisiert
label_last_updates_plural: %d zuletzt aktualisierten label_last_updates_plural: %d zuletzt aktualisierten
label_registered_on: Angemeldet am label_registered_on: Angemeldet am
label_activity: Aktivität label_activity: Aktivität
label_overall_activity: Aktivität aller Projekte anzeigen
label_new: Neu label_new: Neu
label_logged_as: Angemeldet als label_logged_as: Angemeldet als
label_environment: Environment label_environment: Environment
@@ -326,7 +320,7 @@ label_version: Version
label_version_new: Neue Version label_version_new: Neue Version
label_version_plural: Versionen label_version_plural: Versionen
label_confirmation: Bestätigung label_confirmation: Bestätigung
label_export_to: "Auch abrufbar als:" label_export_to: Export zu
label_read: Lesen... label_read: Lesen...
label_public_projects: Öffentliche Projekte label_public_projects: Öffentliche Projekte
label_open_issues: offen label_open_issues: offen
@@ -351,7 +345,7 @@ label_months_from: Monate ab
label_gantt: Gantt label_gantt: Gantt
label_internal: Intern label_internal: Intern
label_last_changes: %d letzte Änderungen label_last_changes: %d letzte Änderungen
label_change_view_all: Alle Änderungen anzeigen label_change_view_all: Alle Änderungen ansehen
label_personalize_page: Diese Seite anpassen label_personalize_page: Diese Seite anpassen
label_comment: Kommentar label_comment: Kommentar
label_comment_plural: Kommentare label_comment_plural: Kommentare
@@ -475,7 +469,7 @@ label_date_to: Bis
label_language_based: Sprachabhängig label_language_based: Sprachabhängig
label_sort_by: Sortiert nach %s label_sort_by: Sortiert nach %s
label_send_test_email: Test-E-Mail senden label_send_test_email: Test-E-Mail senden
label_feeds_access_key_created_on: Atom-Zugriffsschlüssel vor %s erstellt label_feeds_access_key_created_on: RSS-Zugriffsschlüssel vor %s erstellt
label_module_plural: Module label_module_plural: Module
label_added_time_by: Von %s vor %s hinzugefügt label_added_time_by: Von %s vor %s hinzugefügt
label_updated_time: Vor %s aktualisiert label_updated_time: Vor %s aktualisiert
@@ -506,10 +500,6 @@ label_ldap_authentication: LDAP-Authentifizierung
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_optional_description: Beschreibung (optional) label_optional_description: Beschreibung (optional)
label_add_another_file: Eine weitere Datei hinzufügen label_add_another_file: Eine weitere Datei hinzufügen
label_preferences: Präferenzen
label_chronological_order: in zeitlicher Reihenfolge
label_reverse_chronological_order: in umgekehrter zeitlicher Reihenfolge
label_planning: Terminplanung
button_login: Anmelden button_login: Anmelden
button_submit: OK button_submit: OK
@@ -528,7 +518,7 @@ button_lock: Sperren
button_unlock: Entsperren button_unlock: Entsperren
button_download: Download button_download: Download
button_list: Liste button_list: Liste
button_view: Anzeigen button_view: Ansehen
button_move: Verschieben button_move: Verschieben
button_back: Zurück button_back: Zurück
button_cancel: Abbrechen button_cancel: Abbrechen
@@ -545,7 +535,7 @@ button_reset: Zurücksetzen
button_rename: Umbenennen button_rename: Umbenennen
button_change_password: Kennwort ändern button_change_password: Kennwort ändern
button_copy: Kopieren button_copy: Kopieren
button_annotate: Annotieren button_annotate: Mit Anmerkungen versehen
button_update: Aktualisieren button_update: Aktualisieren
button_configure: Konfigurieren button_configure: Konfigurieren
@@ -618,4 +608,13 @@ default_activity_development: Entwicklung
enumeration_issue_priorities: Ticket-Prioritäten enumeration_issue_priorities: Ticket-Prioritäten
enumeration_doc_categories: Dokumentenkategorien enumeration_doc_categories: Dokumentenkategorien
enumeration_activities: Aktivitäten (Zeiterfassung) enumeration_activities: Aktivitäten (Zeiterfassung)
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' setting_activity_days_default: Days displayed on project activity
label_chronological_order: In chronological order
field_comments_sorting: Display comments
label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferences
setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning
-1
View File
@@ -557,7 +557,6 @@ text_select_mail_notifications: Select actions for which email notifications sho
text_regexp_info: eg. ^[A-Z0-9]+$ text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 means no restriction text_min_max_length_info: 0 means no restriction
text_project_destroy_confirmation: Are you sure you want to delete this project and related data ? text_project_destroy_confirmation: Are you sure you want to delete this project and related data ?
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
text_workflow_edit: Select a role and a tracker to edit the workflow text_workflow_edit: Select a role and a tracker to edit the workflow
text_are_you_sure: Are you sure ? text_are_you_sure: Are you sure ?
text_journal_changed: changed from %s to %s text_journal_changed: changed from %s to %s
+62 -63
View File
@@ -333,8 +333,8 @@ label_revision_plural: Revisiones
label_added: añadido label_added: añadido
label_modified: modificado label_modified: modificado
label_deleted: suprimido label_deleted: suprimido
label_latest_revision: Última revisión label_latest_revision: La revisión más actual
label_latest_revision_plural: Últimas revisiones label_latest_revision_plural: Las revisiones más actuales
label_view_revisions: Ver las revisiones label_view_revisions: Ver las revisiones
label_max_size: Tamaño máximo label_max_size: Tamaño máximo
label_on: de label_on: de
@@ -372,7 +372,7 @@ label_view_diff: Ver diferencias
label_diff_inline: en línea label_diff_inline: en línea
label_diff_side_by_side: cara a cara label_diff_side_by_side: cara a cara
label_options: Opciones label_options: Opciones
label_copy_workflow_from: Copiar flujo de trabajo desde label_copy_workflow_from: Copiar workflow desde
label_permissions_report: Informe de permisos label_permissions_report: Informe de permisos
label_watched_issues: Peticiones monitorizadas label_watched_issues: Peticiones monitorizadas
label_related_issues: Peticiones relacionadas label_related_issues: Peticiones relacionadas
@@ -432,7 +432,7 @@ button_move: Mover
button_back: Atrás button_back: Atrás
button_cancel: Cancelar button_cancel: Cancelar
button_activate: Activar button_activate: Activar
button_sort: Ordenar button_sort: Clasificar
button_log_time: Tiempo dedicado button_log_time: Tiempo dedicado
button_rollback: Volver a esta versión button_rollback: Volver a esta versión
button_watch: Monitorizar button_watch: Monitorizar
@@ -448,7 +448,7 @@ status_locked: bloqueado
text_select_mail_notifications: Seleccionar los eventos a notificar text_select_mail_notifications: Seleccionar los eventos a notificar
text_regexp_info: eg. ^[A-Z0-9]+$ text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 para ninguna restricción text_min_max_length_info: 0 para ninguna restricción
text_project_destroy_confirmation: ¿Estás seguro de querer eliminar el proyecto? text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ?
text_workflow_edit: Seleccionar un flujo de trabajo para actualizar text_workflow_edit: Seleccionar un flujo de trabajo para actualizar
text_are_you_sure: ¿ Estás seguro ? text_are_you_sure: ¿ Estás seguro ?
text_journal_changed: cambiado de %s a %s text_journal_changed: cambiado de %s a %s
@@ -460,7 +460,7 @@ text_tip_task_begin_end_day: tarea que comienza y termina este día
text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos.<br />Una vez guardado, el identificador no puede modificarse.' text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos.<br />Una vez guardado, el identificador no puede modificarse.'
text_caracters_maximum: %d carácteres como máximo. text_caracters_maximum: %d carácteres como máximo.
text_length_between: Longitud entre %d y %d carácteres. text_length_between: Longitud entre %d y %d carácteres.
text_tracker_no_workflow: No hay ningún flujo de trabajo definido para este tracker text_tracker_no_workflow: No hay ningún workflow definido para este tracker
text_unallowed_characters: Carácteres no permitidos text_unallowed_characters: Carácteres no permitidos
text_comma_separated: Múltiples valores permitidos (separados por coma). text_comma_separated: Múltiples valores permitidos (separados por coma).
text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes
@@ -559,65 +559,64 @@ field_searchable: Incluir en las búsquedas
label_display_per_page: 'Por página: %s' label_display_per_page: 'Por página: %s'
setting_per_page_options: Objetos por página setting_per_page_options: Objetos por página
label_age: Edad label_age: Edad
notice_default_data_loaded: Configuración por defecto cargada correctamente. notice_default_data_loaded: Default configuration successfully loaded.
text_load_default_configuration: Cargar la configuración por defecto text_load_default_configuration: Load the default configuration
text_no_configuration_data: "Todavía no se han configurado roles, ni trackers, ni estados y flujo de trabajo asociado a peticiones. Se recomiendo encarecidamente cargar la configuración por defecto. Una vez cargada, podrá modificarla." text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %s" error_can_t_load_default_data: "Default configuration could not be loaded: %s"
button_update: Actualizar button_update: Update
label_change_properties: Cambiar propiedades label_change_properties: Change properties
label_general: General label_general: General
label_repository_plural: Repositorios label_repository_plural: Repositories
label_associated_revisions: Revisiones asociadas label_associated_revisions: Associated revisions
setting_user_format: Formato de nombre de usuario setting_user_format: Users display format
text_status_changed_by_changeset: Aplicado en los cambios %s text_status_changed_by_changeset: Applied in changeset %s.
label_more: Más label_more: More
text_issues_destroy_confirmation: '¿Seguro que quiere borrar las peticiones seleccionadas?' text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_scm: SCM label_scm: SCM
text_select_project_modules: 'Seleccione los módulos a activar para este proyecto:' text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: Petición añadida label_issue_added: Issue added
label_issue_updated: Petición actualizada label_issue_updated: Issue updated
label_document_added: Documento añadido label_document_added: Document added
label_message_posted: Mensaje añadido label_message_posted: Message added
label_file_added: Fichero añadido label_file_added: File added
label_news_added: Noticia añadida label_news_added: News added
project_module_boards: Foros project_module_boards: Boards
project_module_issue_tracking: Peticiones project_module_issue_tracking: Issue tracking
project_module_wiki: Wiki project_module_wiki: Wiki
project_module_files: Ficheros project_module_files: Files
project_module_documents: Documentos project_module_documents: Documents
project_module_repository: Repositorio project_module_repository: Repository
project_module_news: Noticias project_module_news: News
project_module_time_tracking: Control de tiempo project_module_time_tracking: Time tracking
text_file_repository_writable: Se puede escribir en el repositorio text_file_repository_writable: File repository writable
text_default_administrator_account_changed: Cuenta de administrador por defecto modificada text_default_administrator_account_changed: Default administrator account changed
text_rmagick_available: RMagick disponible (opcional) text_rmagick_available: RMagick available (optional)
button_configure: Configurar button_configure: Configure
label_plugins: Plugins label_plugins: Plugins
label_ldap_authentication: Autenticación LDAP label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_this_month: este mes label_this_month: this month
label_last_n_days: últimos %d días label_last_n_days: last %d days
label_all_time: todo el tiempo label_all_time: all time
label_this_year: este año label_this_year: this year
label_date_range: Rango de fechas label_date_range: Date range
label_last_week: última semana label_last_week: last week
label_yesterday: ayer label_yesterday: yesterday
label_last_month: último mes label_last_month: last month
label_add_another_file: Añadir otro fichero label_add_another_file: Add another file
label_optional_description: Descripción opcional label_optional_description: Optional description
text_destroy_time_entries_question: Existen %.02f horas asignadas a la petición que quiere borrar. ¿Qué quiere hacer ? text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ?
error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto' error_issue_not_found_in_project: 'The issue was not found or does not belong to this project'
text_assign_time_entries_to_project: Asignar las horas al proyecto text_assign_time_entries_to_project: Assign reported hours to the project
text_destroy_time_entries: Borrar las horas text_destroy_time_entries: Delete reported hours
text_reassign_time_entries: 'Reasignar las horas a esta petición:' text_reassign_time_entries: 'Reassign reported hours to this issue:'
setting_activity_days_default: Días a mostrar en la actividad de proyecto setting_activity_days_default: Days displayed on project activity
label_chronological_order: En orden cronológico label_chronological_order: In chronological order
field_comments_sorting: Mostrar comentarios field_comments_sorting: Display comments
label_reverse_chronological_order: En orden cronológico inverso label_reverse_chronological_order: In reverse chronological order
label_preferences: Preferencias label_preferences: Preferences
setting_display_subprojects_issues: Mostrar peticiones de un subproyecto en el proyecto padre por defecto setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: Actividad global label_overall_activity: Overall activity
setting_default_projects_public: Los proyectos nuevos son públicos por defecto setting_default_projects_public: New projects are public by default
error_scm_annotate: "No existe la entrada o no ha podido ser anotada" error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planificación label_planning: Planning
text_subprojects_destroy_warning: 'Sus subprojectos: %s también se eliminarán'
+3 -4
View File
@@ -614,7 +614,6 @@ field_comments_sorting: Näytä kommentit
label_reverse_chronological_order: Käänteisessä aikajärjestyksessä label_reverse_chronological_order: Käänteisessä aikajärjestyksessä
label_preferences: Asetukset label_preferences: Asetukset
setting_default_projects_public: Uudet projektit ovat oletuksena julkisia setting_default_projects_public: Uudet projektit ovat oletuksena julkisia
label_overall_activity: Kokonaishistoria label_overall_activity: Kokonaisaktiviteetti
error_scm_annotate: "Merkintää ei ole tai siihen ei voi lisätä selityksiä." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Suunnittelu label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+1 -2
View File
@@ -556,8 +556,7 @@ status_locked: vérouillé
text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée
text_regexp_info: ex. ^[A-Z0-9]+$ text_regexp_info: ex. ^[A-Z0-9]+$
text_min_max_length_info: 0 pour aucune restriction text_min_max_length_info: 0 pour aucune restriction
text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et toutes ses données ? text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et tout ce qui lui est rattaché ?
text_subprojects_destroy_warning: 'Ses sous-projets: %s seront également supprimés.'
text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow
text_are_you_sure: Etes-vous sûr ? text_are_you_sure: Etes-vous sûr ?
text_journal_changed: changé de %s à %s text_journal_changed: changé de %s à %s
+100 -101
View File
@@ -76,7 +76,7 @@ notice_failed_to_save_issues: "נכשרת בשמירת %d נושא\ים ב %d נ
notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך." notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך."
error_scm_not_found: כניסה ו\או גירסא אינם קיימים במאגר. error_scm_not_found: כניסה ו\או גירסא אינם קיימים במאגר.
error_scm_command_failed: "ארעה שגיאה בעת ניסון גישה למאגר: %s" error_scm_command_failed: "An error occurred when trying to access the repository: %s"
mail_subject_lost_password: סיסמת ה-%s שלך mail_subject_lost_password: סיסמת ה-%s שלך
mail_body_lost_password: 'לשינו סיסמת ה-Redmine שלך,לחץ על הקישור הבא:' mail_body_lost_password: 'לשינו סיסמת ה-Redmine שלך,לחץ על הקישור הבא:'
@@ -98,7 +98,7 @@ field_filesize: גודל
field_downloads: הורדות field_downloads: הורדות
field_author: כותב field_author: כותב
field_created_on: נוצר field_created_on: נוצר
field_updated_on: עודכן field_updated_on: עודגן
field_field_format: פורמט field_field_format: פורמט
field_is_for_all: לכל הפרויקטים field_is_for_all: לכל הפרויקטים
field_possible_values: ערכים אפשריים field_possible_values: ערכים אפשריים
@@ -119,7 +119,7 @@ field_subject: שם נושא
field_due_date: תאריך סיום field_due_date: תאריך סיום
field_assigned_to: מוצב ל field_assigned_to: מוצב ל
field_priority: עדיפות field_priority: עדיפות
field_fixed_version: גירסאת יעד field_fixed_version: Target version
field_user: מתשמש field_user: מתשמש
field_role: תפקיד field_role: תפקיד
field_homepage: דף הבית field_homepage: דף הבית
@@ -140,7 +140,7 @@ field_version: גירסא
field_type: סוג field_type: סוג
field_host: שרת field_host: שרת
field_port: פורט field_port: פורט
field_account: חשבון field_account: חשבום
field_base_dn: בסיס DN field_base_dn: בסיס DN
field_attr_login: תכונת התחברות field_attr_login: תכונת התחברות
field_attr_firstname: תכונת שם פרטים field_attr_firstname: תכונת שם פרטים
@@ -182,7 +182,7 @@ setting_text_formatting: עיצוב טקסט
setting_wiki_compression: כיווץ היסטורית WIKI setting_wiki_compression: כיווץ היסטורית WIKI
setting_feeds_limit: גבול תוכן הזנות setting_feeds_limit: גבול תוכן הזנות
setting_autofetch_changesets: משיכה אוטומתי של עידכונים setting_autofetch_changesets: משיכה אוטומתי של עידכונים
setting_sys_api_enabled: אפשר WS לניהול המאגר setting_sys_api_enabled: Enable WS for repository management
setting_commit_ref_keywords: מילות מפתח מקשרות setting_commit_ref_keywords: מילות מפתח מקשרות
setting_commit_fix_keywords: מילות מפתח מתקנות setting_commit_fix_keywords: מילות מפתח מתקנות
setting_autologin: חיבור אוטומטי setting_autologin: חיבור אוטומטי
@@ -233,7 +233,7 @@ label_information_plural: מידע
label_please_login: התחבר בבקשה label_please_login: התחבר בבקשה
label_register: הרשמה label_register: הרשמה
label_password_lost: אבדה הסיסמה? label_password_lost: אבדה הסיסמה?
label_home: דף הבית label_home: דך הבית
label_my_page: הדף שלי label_my_page: הדף שלי
label_my_account: השבון שלי label_my_account: השבון שלי
label_my_projects: הפרויקטים שלי label_my_projects: הפרויקטים שלי
@@ -259,7 +259,7 @@ label_subproject_plural: תת-פרויקטים
label_min_max_length: אורך מינימאלי - מקסימאלי label_min_max_length: אורך מינימאלי - מקסימאלי
label_list: רשימה label_list: רשימה
label_date: תאריך label_date: תאריך
label_integer: מספר שלם label_integer: מספר שלים
label_boolean: ערך בוליאני label_boolean: ערך בוליאני
label_string: טקסט label_string: טקסט
label_text: טקסט ארוך label_text: טקסט ארוך
@@ -269,7 +269,7 @@ label_download: הורדה %d
label_download_plural: %d הורדות label_download_plural: %d הורדות
label_no_data: אין מידע להציג label_no_data: אין מידע להציג
label_change_status: שנה מצב label_change_status: שנה מצב
label_history: היסטוריה label_history: הידטוריה
label_attachment: קובץ label_attachment: קובץ
label_attachment_new: קובץ חדש label_attachment_new: קובץ חדש
label_attachment_delete: מחק קובץ label_attachment_delete: מחק קובץ
@@ -279,7 +279,7 @@ label_report_plural: דו"חות
label_news: חדשות label_news: חדשות
label_news_new: הוסף חדשות label_news_new: הוסף חדשות
label_news_plural: חדשות label_news_plural: חדשות
label_news_latest: חדשות אחרונות label_news_latest: חדשות חדשות
label_news_view_all: צפה בכל החדשות label_news_view_all: צפה בכל החדשות
label_change_log: דו"ח שינויים label_change_log: דו"ח שינויים
label_settings: הגדרות label_settings: הגדרות
@@ -419,7 +419,7 @@ label_reply_plural: השבות
label_send_information: שלח מידע על חשבון למשתמש label_send_information: שלח מידע על חשבון למשתמש
label_year: שנה label_year: שנה
label_month: חודש label_month: חודש
label_week: שבוע label_week: שבו
label_date_from: מאת label_date_from: מאת
label_date_to: אל label_date_to: אל
label_language_based: מבוסס שפה label_language_based: מבוסס שפה
@@ -444,7 +444,7 @@ button_save: שמור
button_check_all: בחר הכל button_check_all: בחר הכל
button_uncheck_all: בחר כלום button_uncheck_all: בחר כלום
button_delete: מחק button_delete: מחק
button_create: צור button_create: צוק
button_test: בדוק button_test: בדוק
button_edit: ערוך button_edit: ערוך
button_add: הוסף button_add: הוסף
@@ -454,13 +454,13 @@ button_clear: נקה
button_lock: נעל button_lock: נעל
button_unlock: בטל נעילה button_unlock: בטל נעילה
button_download: הורד button_download: הורד
button_list: רשימה button_list: קשימה
button_view: צפה button_view: צפה
button_move: הזז button_move: הזז
button_back: הקודם button_back: הקודם
button_cancel: בטח button_cancel: בטח
button_activate: הפעל button_activate: הפעל
button_sort: מיין button_sort: מין
button_log_time: זמן לוג button_log_time: זמן לוג
button_rollback: חזור לגירסא זו button_rollback: חזור לגירסא זו
button_watch: צפה button_watch: צפה
@@ -526,95 +526,94 @@ default_activity_development: פיתוח
enumeration_issue_priorities: עדיפות נושאים enumeration_issue_priorities: עדיפות נושאים
enumeration_doc_categories: קטגוריות מסמכים enumeration_doc_categories: קטגוריות מסמכים
enumeration_activities: פעילויות (מעקב אחר זמנים) enumeration_activities: פעילויות (מעקב אחר זמנים)
label_search_titles_only: חפש בכותרות בלבד label_search_titles_only: Search titles only
label_nobody: אף אחד label_nobody: nobody
button_change_password: שנה סיסמא button_change_password: Change password
text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או מוצבים אליך)." text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)."
label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..." label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי" label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "רק לנושאים שאני צופה או קשור אליהם" label_user_mail_option_none: "Only for things I watch or I'm involved in"
setting_emails_footer: תחתית דוא"ל setting_emails_footer: Emails footer
label_float: צף label_float: Float
button_copy: העתק button_copy: Copy
mail_body_account_information_external: אתה יכול להשתמש בחשבון "%s" כדי להתחבר mail_body_account_information_external: You can use your "%s" account to log in.
mail_body_account_information: פרטי החשבון שלך mail_body_account_information: Your account information
setting_protocol: פרוטוקול setting_protocol: Protocol
label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע" label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: פורמט זמן setting_time_format: Time format
label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל label_registration_activation_by_email: account activation by email
mail_subject_account_activation_request: בקשת הפעלה לחשבון %s mail_subject_account_activation_request: %s account activation request
mail_body_account_activation_request: 'משתמש חדש (%s) נרשם. החשבון שלו מחכה לאישור שלך:' mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
label_registration_automatic_activation: הפעלת חשבון אוטומטית label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: הפעלת חשבון ידנית label_registration_manual_activation: manual account activation
notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: איזור זמן field_time_zone: Time zone
text_caracters_minimum: חייב להיות לפחות באורך של %d תווים. text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: מוסתר (bcc) setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: הוסף תיאור מסגרת button_annotate: Annotate
label_issues_by: נושאים של %s label_issues_by: Issues by %s
field_searchable: ניתן לחיפוש field_searchable: Searchable
label_display_per_page: 'לכל דף: %s' label_display_per_page: 'Per page: %s'
setting_per_page_options: אפשרויות אוביקטים לפי דף setting_per_page_options: Objects per page options
label_age: גיל label_age: Age
notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות. notice_default_data_loaded: Default configuration successfully loaded.
text_load_default_configuration: טען את אפשרויות ברירת המחדל text_load_default_configuration: Load the default configuration
text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. יהיה באפשרותך לשנותו לאחר שיטען." text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded."
error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: %s" error_can_t_load_default_data: "Default configuration could not be loaded: %s"
button_update: עדכן button_update: Update
label_change_properties: שנה מאפיינים label_change_properties: Change properties
label_general: כללי label_general: General
label_repository_plural: מאגרים label_repository_plural: Repositories
label_associated_revisions: שינויים קשורים label_associated_revisions: Associated revisions
setting_user_format: פורמט הצגת משתמשים setting_user_format: Users display format
text_status_changed_by_changeset: הוחל בסדרת השינויים %s. text_status_changed_by_changeset: Applied in changeset %s.
label_more: עוד label_more: More
text_issues_destroy_confirmation: 'האם את\ה בטוח שברצונך למחוק את הנושא\ים ?' text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_scm: SCM label_scm: SCM
text_select_project_modules: 'בחר מודולים להחיל על פקרויקט זה:' text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: נושא הוסף label_issue_added: Issue added
label_issue_updated: נושא עודכן label_issue_updated: Issue updated
label_document_added: מוסמך הוסף label_document_added: Document added
label_message_posted: הודעה הוספה label_message_posted: Message added
label_file_added: קובץ הוסף label_file_added: File added
label_news_added: חדשות הוספו label_news_added: News added
project_module_boards: לוחות project_module_boards: Boards
project_module_issue_tracking: מעקב נושאים project_module_issue_tracking: Issue tracking
project_module_wiki: Wiki project_module_wiki: Wiki
project_module_files: קבצים project_module_files: Files
project_module_documents: מסמכים project_module_documents: Documents
project_module_repository: מאגר project_module_repository: Repository
project_module_news: חדשות project_module_news: News
project_module_time_tracking: מעקב אחר זמנים project_module_time_tracking: Time tracking
text_file_repository_writable: מאגר הקבצים ניתן לכתיבה text_file_repository_writable: File repository writable
text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה text_default_administrator_account_changed: Default administrator account changed
text_rmagick_available: RMagick available (optional) text_rmagick_available: RMagick available (optional)
button_configure: אפשרויות button_configure: Configure
label_plugins: פלאגינים label_plugins: Plugins
label_ldap_authentication: אימות LDAP label_ldap_authentication: LDAP authentication
label_downloads_abbr: D/L label_downloads_abbr: D/L
label_this_month: החודש label_this_month: this month
label_last_n_days: ב-%d ימים אחרונים label_last_n_days: last %d days
label_all_time: תמיד label_all_time: all time
label_this_year: השנה label_this_year: this year
label_date_range: טווח תאריכים label_date_range: Date range
label_last_week: שבוע שעבר label_last_week: last week
label_yesterday: אתמול label_yesterday: yesterday
label_last_month: חודש שעבר label_last_month: last month
label_add_another_file: הוסף עוד קובץ label_add_another_file: Add another file
label_optional_description: תיאור רשות label_optional_description: Optional description
text_destroy_time_entries_question: %.02f שעות דווחו על הנושים שאת\ה עומד\ת למחוק. מה ברצונך לעשות ? text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ?
error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט' error_issue_not_found_in_project: 'The issue was not found or does not belong to this project'
text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה text_assign_time_entries_to_project: Assign reported hours to the project
text_destroy_time_entries: מחק שעות שדווחו text_destroy_time_entries: Delete reported hours
text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:' text_reassign_time_entries: 'Reassign reported hours to this issue:'
setting_activity_days_default: ימים המוצגים על פעילות הפרויקט setting_activity_days_default: Days displayed on project activity
label_chronological_order: בסדר כרונולוגי label_chronological_order: In chronological order
field_comments_sorting: הצג הערות field_comments_sorting: Display comments
label_reverse_chronological_order: בסדר כרונולוגי הפוך label_reverse_chronological_order: In reverse chronological order
label_preferences: העדפות label_preferences: Preferences
setting_display_subprojects_issues: הצג נושאים של תת פרויקטים כברירת מחדל setting_display_subprojects_issues: Display subprojects issues on main projects by default
label_overall_activity: פעילות כוללת label_overall_activity: Overall activity
setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל setting_default_projects_public: New projects are public by default
error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: תכנון label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ label_overall_activity: 全ての活動
setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする
error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。" error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。"
label_planning: 計画 label_planning: 計画
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+9 -10
View File
@@ -80,7 +80,7 @@ notice_default_data_loaded: Standardkonfigurasjonen lastet inn.
error_can_t_load_default_data: "Standardkonfigurasjonen kunne ikke lastes inn: %s" error_can_t_load_default_data: "Standardkonfigurasjonen kunne ikke lastes inn: %s"
error_scm_not_found: "Elementet og/eller revisjonen eksisterer ikke i depoet." error_scm_not_found: "Elementet og/eller revisjonen eksisterer ikke i depoet."
error_scm_command_failed: "En feil oppstod under tilkobling til depoet: %s" error_scm_command_failed: "En feil oppstod under tilkobling til depoet: %s"
error_scm_annotate: "Elementet eksisterer ikke, eller kan ikke noteres." error_scm_annotate: "Elementet eksisterer ikke, eller kan ikke annoteres."
error_issue_not_found_in_project: 'Saken eksisterer ikke, eller hører ikke til dette prosjektet' error_issue_not_found_in_project: 'Saken eksisterer ikke, eller hører ikke til dette prosjektet'
mail_subject_lost_password: Ditt %s passord mail_subject_lost_password: Ditt %s passord
@@ -137,7 +137,7 @@ field_parent: Underprosjekt til
field_is_in_chlog: Vises i endringslogg field_is_in_chlog: Vises i endringslogg
field_is_in_roadmap: Vises i veikart field_is_in_roadmap: Vises i veikart
field_login: Brukernavn field_login: Brukernavn
field_mail_notification: E-post-varsling field_mail_notification: E-post varsling
field_admin: Administrator field_admin: Administrator
field_last_login_on: Sist innlogget field_last_login_on: Sist innlogget
field_language: Språk field_language: Språk
@@ -165,7 +165,7 @@ field_url: URL
field_start_page: Startside field_start_page: Startside
field_subproject: Underprosjekt field_subproject: Underprosjekt
field_hours: Timer field_hours: Timer
field_activity: Aktivitet field_activity: Activitet
field_spent_on: Dato field_spent_on: Dato
field_identifier: Identifikasjon field_identifier: Identifikasjon
field_is_filter: Brukes som filter field_is_filter: Brukes som filter
@@ -282,7 +282,7 @@ label_last_updates: Sist oppdatert
label_last_updates_plural: %d siste oppdaterte label_last_updates_plural: %d siste oppdaterte
label_registered_on: Registrert label_registered_on: Registrert
label_activity: Aktivitet label_activity: Aktivitet
label_overall_activity: All aktivitet label_overall_activity: Total aktivitet
label_new: Ny label_new: Ny
label_logged_as: Innlogget som label_logged_as: Innlogget som
label_environment: Miljø label_environment: Miljø
@@ -352,7 +352,7 @@ label_gantt: Gantt
label_internal: Intern label_internal: Intern
label_last_changes: siste %d endringer label_last_changes: siste %d endringer
label_change_view_all: Vis alle endringer label_change_view_all: Vis alle endringer
label_personalize_page: Tilpass denne siden label_personalize_page: Tilrettelegg denne siden
label_comment: Kommentar label_comment: Kommentar
label_comment_plural: Kommentarer label_comment_plural: Kommentarer
label_comment_add: Legg til kommentar label_comment_add: Legg til kommentar
@@ -545,7 +545,7 @@ button_reset: Nullstill
button_rename: Endre navn button_rename: Endre navn
button_change_password: Endre passord button_change_password: Endre passord
button_copy: Kopier button_copy: Kopier
button_annotate: Notér button_annotate: Annotér
button_update: Oppdater button_update: Oppdater
button_configure: Konfigurer button_configure: Konfigurer
@@ -557,7 +557,6 @@ text_select_mail_notifications: Velg hendelser som skal varsles med e-post.
text_regexp_info: eg. ^[A-Z0-9]+$ text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 betyr ingen begrensning text_min_max_length_info: 0 betyr ingen begrensning
text_project_destroy_confirmation: Er du sikker på at du vil slette dette prosjekter og alle relatert data ? text_project_destroy_confirmation: Er du sikker på at du vil slette dette prosjekter og alle relatert data ?
text_subprojects_destroy_warning: 'Underprojekt(ene): %s vil også bli slettet.'
text_workflow_edit: Velg en rolle og en sakstype for å endre arbeidsflyten text_workflow_edit: Velg en rolle og en sakstype for å endre arbeidsflyten
text_are_you_sure: Er du sikker ? text_are_you_sure: Er du sikker ?
text_journal_changed: endret fra %s til %s text_journal_changed: endret fra %s til %s
@@ -566,7 +565,7 @@ text_journal_deleted: slettet
text_tip_task_begin_day: oppgaven starter denne dagen text_tip_task_begin_day: oppgaven starter denne dagen
text_tip_task_end_day: oppgaven avsluttes denne dagen text_tip_task_end_day: oppgaven avsluttes denne dagen
text_tip_task_begin_end_day: oppgaven starter og avsluttes denne dagen text_tip_task_begin_end_day: oppgaven starter og avsluttes denne dagen
text_project_identifier_info: 'Små bokstaver (a-z), nummer og bindestrek tillatt.<br />Identifikatoren kan ikke endres etter den er lagret.' text_project_identifier_info: 'Små bokstaver (a-z), nummer og binde-/understrek tillat.<br />Identifikatoren kan ikke endres etter den er lagret.'
text_caracters_maximum: %d tegn maksimum. text_caracters_maximum: %d tegn maksimum.
text_caracters_minimum: Må være minst %d tegn langt. text_caracters_minimum: Må være minst %d tegn langt.
text_length_between: Lengde mellom %d og %d tegn. text_length_between: Lengde mellom %d og %d tegn.
@@ -587,8 +586,8 @@ text_status_changed_by_changeset: Brukt i endringssett %s.
text_issues_destroy_confirmation: 'Er du sikker på at du vil slette valgte sak(er) ?' text_issues_destroy_confirmation: 'Er du sikker på at du vil slette valgte sak(er) ?'
text_select_project_modules: 'Velg moduler du vil aktivere for dette prosjektet:' text_select_project_modules: 'Velg moduler du vil aktivere for dette prosjektet:'
text_default_administrator_account_changed: Standard administrator-konto er endret text_default_administrator_account_changed: Standard administrator-konto er endret
text_file_repository_writable: Fil-arkivet er skrivbart text_file_repository_writable: Fil-depotet er skrivbart
text_rmagick_available: RMagick er tilgjengelig (valgfritt) text_rmagick_available: RMagick tilgjengelig (valgfritt)
text_destroy_time_entries_question: %.02f timer er ført på sakene du er i ferd med å slette. Hva vil du gjøre ? text_destroy_time_entries_question: %.02f timer er ført på sakene du er i ferd med å slette. Hva vil du gjøre ?
text_destroy_time_entries: Slett førte timer text_destroy_time_entries: Slett førte timer
text_assign_time_entries_to_project: Overfør førte timer til prosjektet text_assign_time_entries_to_project: Overfør førte timer til prosjektet
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Ogólna aktywność
setting_default_projects_public: Nowe projekty są domyślnie publiczne setting_default_projects_public: Nowe projekty są domyślnie publiczne
error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji." error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -617,4 +617,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+2 -3
View File
@@ -619,6 +619,5 @@ label_preferences: Предпочтения
setting_display_subprojects_issues: Отображение подпроектов по умолчанию setting_display_subprojects_issues: Отображение подпроектов по умолчанию
label_overall_activity: Сводная активность label_overall_activity: Сводная активность
setting_default_projects_public: Новые проекты являются публичными setting_default_projects_public: Новые проекты являются публичными
error_scm_annotate: "Данные отсутствуют или не могут быть подписаны." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Планирование label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -619,4 +619,3 @@ label_overall_activity: Overall activity
setting_default_projects_public: New projects are public by default setting_default_projects_public: New projects are public by default
error_scm_annotate: "The entry does not exist or can not be annotated." error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ default_activity_development: 開發
enumeration_issue_priorities: 項目優先權 enumeration_issue_priorities: 項目優先權
enumeration_doc_categories: 文件分類 enumeration_doc_categories: 文件分類
enumeration_activities: 活動 (時間追蹤) enumeration_activities: 活動 (時間追蹤)
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
-1
View File
@@ -618,4 +618,3 @@ default_activity_development: 开发
enumeration_issue_priorities: 问题优先级 enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别 enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪) enumeration_activities: 活动(时间跟踪)
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'
+1 -1
View File
@@ -1134,7 +1134,7 @@ class RedCloth < String
ALLOWED_TAGS = %w(redpre pre code) ALLOWED_TAGS = %w(redpre pre code)
def escape_html_tags(text) def escape_html_tags(text)
text.gsub!(%r{<(\/?(\w+)[^>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "&lt;#{$1}#{'&gt;' if $3}" } text.gsub!(%r{<((\/?)(\w+))}) {|m| ALLOWED_TAGS.include?($3) ? "<#{$1}" : "&lt;#{$1}" }
end end
end end
-1
View File
@@ -1,7 +1,6 @@
require 'redmine/access_control' require 'redmine/access_control'
require 'redmine/menu_manager' require 'redmine/menu_manager'
require 'redmine/mime_type' require 'redmine/mime_type'
require 'redmine/core_ext'
require 'redmine/themes' require 'redmine/themes'
require 'redmine/plugin' require 'redmine/plugin'
-1
View File
@@ -1 +0,0 @@
Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) }
-5
View File
@@ -1,5 +0,0 @@
require File.dirname(__FILE__) + '/string/conversions'
class String #:nodoc:
include Redmine::CoreExtensions::String::Conversions
end
@@ -1,40 +0,0 @@
# redMine - project management software
# Copyright (C) 2008 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module Redmine #:nodoc:
module CoreExtensions #:nodoc:
module String #:nodoc:
# Custom string conversions
module Conversions
# Parses hours format and returns a float
def to_hours
s = self.dup
s.strip!
unless s =~ %r{^[\d\.,]+$}
# 2:30 => 2.5
s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 }
# 2h30, 2h, 30m => 2.5, 2, 0.5
s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] }
end
# 2,5 => 2.5
s.gsub!(',', '.')
s.to_f
end
end
end
end
end
+2 -11
View File
@@ -59,17 +59,8 @@ module Redmine
# Returns the entry identified by path and revision identifier # Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository # or nil if entry doesn't exist in the repository
def entry(path=nil, identifier=nil) def entry(path=nil, identifier=nil)
parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} e = entries(path, identifier)
search_path = parts[0..-2].join('/') e ? e.first : nil
search_name = parts[-1]
if search_path.blank? && search_name.blank?
# Root entry
Entry.new(:path => '', :kind => 'dir')
else
# Search for the entry in the parent directory
es = entries(search_path, identifier)
es ? es.detect {|e| e.name == search_name} : nil
end
end end
# Returns an Entries collection # Returns an Entries collection
@@ -44,6 +44,18 @@ module Redmine
return nil return nil
end end
# Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository
def entry(path=nil, identifier=nil)
path ||= ''
parts = path.split(%r{[\/\\]}).select {|p| !p.blank?}
if parts.size > 0
parent = parts[0..-2].join('/')
entries = entries(parent, identifier)
entries ? entries.detect {|e| e.name == parts.last} : nil
end
end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
+10 -3
View File
@@ -56,6 +56,15 @@ module Redmine
CvsRevisionHelper.new(revision).prevRev CvsRevisionHelper.new(revision).prevRev
end end
# Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository
# this method returns all revisions from one single SCM-Entry
def entry(path=nil, identifier="HEAD")
e = entries(path, identifier)
logger.debug("<cvs-result> #{e.first.inspect}") if e
e ? e.first : nil
end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
# this method is used by the repository-browser (aka LIST) # this method is used by the repository-browser (aka LIST)
@@ -63,9 +72,7 @@ module Redmine
logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'" logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
path_with_project="#{url}#{with_leading_slash(path)}" path_with_project="#{url}#{with_leading_slash(path)}"
entries = Entries.new entries = Entries.new
cmd = "#{CVS_BIN} -d #{root_url} rls -ed" cmd = "#{CVS_BIN} -d #{root_url} rls -ed #{path_with_project}"
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
cmd << " #{path_with_project}"
shellout(cmd) do |io| shellout(cmd) do |io|
io.each_line(){|line| io.each_line(){|line|
fields=line.chop.split('/',-1) fields=line.chop.split('/',-1)
+8 -3
View File
@@ -40,15 +40,20 @@ module Redmine
rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil
end end
# Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository
def entry(path=nil, identifier=nil)
e = entries(path, identifier)
e ? e.first : nil
end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path_prefix = (path.blank? ? '' : "#{path}/") path_prefix = (path.blank? ? '' : "#{path}/")
path = '.' if path.blank? path = '.' if path.blank?
entries = Entries.new entries = Entries.new
cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output" cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output #{path}"
cmd << " --match \"hash #{identifier}\"" if identifier
cmd << " #{path}"
shellout(cmd) do |io| shellout(cmd) do |io|
begin begin
doc = REXML::Document.new(io) doc = REXML::Document.new(io)
+9 -1
View File
@@ -79,7 +79,7 @@ module Redmine
rev = Revision.new({:identifier => changeset[:commit], rev = Revision.new({:identifier => changeset[:commit],
:scmid => changeset[:commit], :scmid => changeset[:commit],
:author => changeset[:author], :author => changeset[:author],
:time => (changeset[:date] ? Time.parse(changeset[:date]) : nil), :time => Time.parse(changeset[:date]),
:message => changeset[:description], :message => changeset[:description],
:paths => files :paths => files
}) })
@@ -132,6 +132,14 @@ module Redmine
entries.sort_by_name entries.sort_by_name
end end
def entry(path=nil, identifier=nil)
path ||= ''
search_path = path.split('/')[0..-2].join('/')
entry_name = path.split('/').last
e = entries(search_path, identifier)
e ? e.detect{|entry| entry.name == entry_name} : nil
end
def revisions(path, identifier_from, identifier_to, options={}) def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw " cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw "
+22 -44
View File
@@ -60,6 +60,14 @@ module Redmine
entries.sort_by_name entries.sort_by_name
end end
def entry(path=nil, identifier=nil)
path ||= ''
search_path = path.split('/')[0..-2].join('/')
entry_name = path.split('/').last
e = entries(search_path, identifier)
e ? e.detect{|entry| entry.name == entry_name} : nil
end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
revisions = Revisions.new revisions = Revisions.new
cmd = "#{HG_BIN} -v --encoding utf8 -R #{target('')} log" cmd = "#{HG_BIN} -v --encoding utf8 -R #{target('')} log"
@@ -80,7 +88,13 @@ module Redmine
value = $2 value = $2
if parsing_descr && line_feeds > 1 if parsing_descr && line_feeds > 1
parsing_descr = false parsing_descr = false
revisions << build_revision_from_changeset(changeset) revisions << Revision.new({:identifier => changeset[:changeset].split(':').first.to_i,
:scmid => changeset[:changeset].split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => changeset[:files].to_s.split.collect{|path| {:action => 'X', :path => "/#{path}"}}
})
changeset = {} changeset = {}
end end
if !parsing_descr if !parsing_descr
@@ -97,8 +111,13 @@ module Redmine
line_feeds += 1 if line.chomp.empty? line_feeds += 1 if line.chomp.empty?
end end
end end
# Add the last changeset if there is one left revisions << Revision.new({:identifier => changeset[:changeset].split(':').first.to_i,
revisions << build_revision_from_changeset(changeset) if changeset[:date] :scmid => changeset[:changeset].split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => changeset[:files].to_s.split.collect{|path| {:action => 'X', :path => "/#{path}"}}
})
end end
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
revisions revisions
@@ -152,47 +171,6 @@ module Redmine
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
blame blame
end end
private
# Builds a revision objet from the changeset returned by hg command
def build_revision_from_changeset(changeset)
rev_id = changeset[:changeset].to_s.split(':').first.to_i
# Changes
paths = (rev_id == 0) ?
# Can't get changes for revision 0 with hg status
changeset[:files].to_s.split.collect{|path| {:action => 'A', :path => "/#{path}"}} :
status(rev_id)
Revision.new({:identifier => rev_id,
:scmid => changeset[:changeset].to_s.split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => paths
})
end
# Returns the file changes for a given revision
def status(rev_id)
cmd = "#{HG_BIN} -R #{target('')} status --rev #{rev_id.to_i - 1}:#{rev_id.to_i}"
result = []
shellout(cmd) do |io|
io.each_line do |line|
action, file = line.chomp.split
next unless action && file
file.gsub!("\\", "/")
case action
when 'R'
result << { :action => 'D' , :path => "/#{file}" }
else
result << { :action => action, :path => "/#{file}" }
end
end
end
result
end
end end
end end
end end
+15 -6
View File
@@ -51,11 +51,18 @@ module Redmine
return nil return nil
end end
# Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository
def entry(path=nil, identifier=nil)
e = entries(path, identifier)
e ? e.first : nil
end
# Returns an Entries collection # Returns an Entries collection
# or nil if the given path doesn't exist in the repository # or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil) def entries(path=nil, identifier=nil)
path ||= '' path ||= ''
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" identifier = 'HEAD' unless identifier and identifier > 0
entries = Entries.new entries = Entries.new
cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}" cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
cmd << credentials_string cmd << credentials_string
@@ -87,8 +94,8 @@ module Redmine
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
path ||= '' path ||= ''
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD" identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1 identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
revisions = Revisions.new revisions = Revisions.new
cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}" cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
cmd << credentials_string cmd << credentials_string
@@ -124,9 +131,11 @@ module Redmine
def diff(path, identifier_from, identifier_to=nil, type="inline") def diff(path, identifier_from, identifier_to=nil, type="inline")
path ||= '' path ||= ''
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : '' if identifier_to and identifier_to.to_i > 0
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1) identifier_to = identifier_to.to_i
else
identifier_to = identifier_from.to_i - 1
end
cmd = "#{SVN_BIN} diff -r " cmd = "#{SVN_BIN} diff -r "
cmd << "#{identifier_to}:" cmd << "#{identifier_to}:"
cmd << "#{identifier_from}" cmd << "#{identifier_from}"
+1 -1
View File
@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 0 MAJOR = 0
MINOR = 7 MINOR = 7
TINY = 0 TINY = 'devel'
def self.revision def self.revision
revision = nil revision = nil
+13 -16
View File
@@ -77,24 +77,21 @@ module Redmine
content_tag('dl', out) content_tag('dl', out)
end end
desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" desc "Include a wiki page. Example:\n\n !{{include(Foo)}}"
macro :include do |obj, args| macro :include do |obj, args|
project = @project if @project && !@project.wiki.nil?
title = args.first.to_s page = @project.wiki.find_page(args.first)
if title =~ %r{^([^\:]+)\:(.*)$} if page && page.content
project_identifier, title = $1, $2 @included_wiki_pages ||= []
project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier) raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
@included_wiki_pages << page.title
out = textilizable(page.content, :text)
@included_wiki_pages.pop
out
else
raise "Page #{args.first} doesn't exist"
end
end end
raise 'Unknow project' unless project && User.current.allowed_to?(:view_wiki_pages, project)
raise 'No wiki for this project' unless !project.wiki.nil?
page = project.wiki.find_page(title)
raise "Page #{args.first} doesn't exist" unless page && page.content
@included_wiki_pages ||= []
raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title)
@included_wiki_pages << page.title
out = textilizable(page.content, :text, :attachments => page.attachments)
@included_wiki_pages.pop
out
end end
end end
end end
Binary file not shown.

Before

Width:  |  Height:  |  Size: 995 B

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 557 B

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