Compare commits

...
25 Commits
Author SHA1 Message Date
Jean-Philippe Lang 7e6d1b6c35 Version set to 1.2.3.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8178 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-10 14:49:48 +00:00
Jean-Philippe Lang 5c4b618bce CHANGELOG updated.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8177 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-10 14:49:10 +00:00
Jean-Philippe Lang 2f87b3bae3 Merged r7920, r7921, r7922 and r7924 from trunk (#9405).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8158 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-10 12:04:47 +00:00
Jean-Philippe Lang 1848fcd91e Merged r8103 from trunk (#9737).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8157 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-10 11:56:13 +00:00
Jean-Philippe Lang 40a14cafbc Merged r7809 from trunk (#9567).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8120 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:58:58 +00:00
Jean-Philippe Lang f252108f30 Merged r7834 from trunk (#9566).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8119 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:57:55 +00:00
Jean-Philippe Lang 6d57380712 Merged r7780 from trunk (#9552).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8118 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:56:49 +00:00
Jean-Philippe Lang 00d1b230e0 Merged r7814 from trunk (#9577).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8117 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:54:05 +00:00
Jean-Philippe Lang d19a0b70e0 Merged r7971 from trunk (#9682).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8116 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:52:31 +00:00
Jean-Philippe Lang 535b5ccf2b Merged r7919 from trunk (#9448).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8115 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 21:49:52 +00:00
Toshi MARUYAMA a441667b8d Merged r8106 from trunk
remove trailing white-spaces from calendar-hr.js

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8108 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 01:21:54 +00:00
Toshi MARUYAMA d4246334e0 Merged r8105 from trunk
convert calendar-hr.js (Croatian) from Windows-1250 to UTF-8.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8107 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-07 01:21:06 +00:00
Toshi MARUYAMA c8c48a7816 Merged r8002 from trunk
Bulgarian translation updated by Ivan Cenov.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8083 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-12-04 22:36:12 +00:00
Jean-Philippe Lang fa894328bb Merged r7983 and r7984 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@8000 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:17:41 +00:00
Jean-Philippe Lang 63e2e52dd3 Merged r7782 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7999 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:14:24 +00:00
Jean-Philippe Lang ff75a959e0 Merged r7779 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7998 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:12:58 +00:00
Jean-Philippe Lang 5d1388db02 Merged r7985 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7997 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:11:54 +00:00
Jean-Philippe Lang 3e4d1fb04f Backported r7982 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7996 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:10:45 +00:00
Jean-Philippe Lang 2858979b69 Merged r7956 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7995 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-29 21:08:06 +00:00
Etienne Massip be09ba039b Merged r7837 from trunk (#9597).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7838 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-18 22:30:32 +00:00
Toshi MARUYAMA a5adecb40c Merge r7797 from trunk
Simplified Chinese "text_git_repository_note" translation updated by Steven Wong.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7801 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-13 06:38:41 +00:00
Toshi MARUYAMA f328373ffd Merge r7796 from trunk
Simplified Chinese translation for 1.2.2 updated by Steven Wong.

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7800 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-13 06:38:08 +00:00
Toshi MARUYAMA 367ad46911 Merge r7795 from trunk
Simplified Chinese translation changed by Steven Wong.

* field_due_date
* permission_rename_wiki_pages
* button_rename

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7799 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-13 06:37:33 +00:00
Toshi MARUYAMA 909cb9ab78 Merge r6699 from trunk
remove trailing white-spaces from config/locales/zh.yml

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7793 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-13 03:46:53 +00:00
Toshi MARUYAMA 8c2869f521 Merge r6698 from trunk
Ruby 1.9: fix parsing error of zh.yml with psych yaml library

git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.2-stable@7792 e93f8b46-1217-0410-a6f0-8f06a7374b81
2011-11-13 03:46:05 +00:00
34 changed files with 295 additions and 106 deletions
+2 -3
View File
@@ -48,9 +48,8 @@ class ContextMenusController < ApplicationController
@projects = @time_entries.collect(&:project).compact.uniq @projects = @time_entries.collect(&:project).compact.uniq
@project = @projects.first if @projects.size == 1 @project = @projects.first if @projects.size == 1
@activities = TimeEntryActivity.shared.active @activities = TimeEntryActivity.shared.active
@can = {:edit => User.current.allowed_to?(:log_time, @projects), @can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects),
:update => User.current.allowed_to?(:log_time, @projects), :delete => User.current.allowed_to?(:edit_time_entries, @projects)
:delete => User.current.allowed_to?(:log_time, @projects)
} }
@back = back_url @back = back_url
render :layout => false render :layout => false
+3 -2
View File
@@ -20,7 +20,8 @@ class SysController < ActionController::Base
def projects def projects
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
render :xml => p.to_xml(:include => :repository) # extra_info attribute from repository breaks activeresource client
render :xml => p.to_xml(:only => [:id, :identifier, :name, :is_public, :status], :include => {:repository => {:only => [:id, :url]}})
end end
def create_project_repository def create_project_repository
@@ -31,7 +32,7 @@ class SysController < ActionController::Base
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
project.repository = Repository.factory(params[:vendor], params[:repository]) project.repository = Repository.factory(params[:vendor], params[:repository])
if project.repository && project.repository.save if project.repository && project.repository.save
render :xml => project.repository, :status => 201 render :xml => project.repository.to_xml(:only => [:id, :url]), :status => 201
else else
render :nothing => true, :status => 422 render :nothing => true, :status => 422
end end
+1 -1
View File
@@ -62,7 +62,7 @@ protected
when 'float' when 'float'
begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end begin; Kernel.Float(value); rescue; errors.add(:value, :invalid) end
when 'date' when 'date'
errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ errors.add(:value, :not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end
when 'list' when 'list'
errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value) errors.add(:value, :inclusion) unless custom_field.possible_values.include?(value)
end end
+1
View File
@@ -809,6 +809,7 @@ class Project < ActiveRecord::Base
new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria") new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria")
new_query.sort_criteria = query.sort_criteria if query.sort_criteria new_query.sort_criteria = query.sort_criteria if query.sort_criteria
new_query.project = self new_query.project = self
new_query.user_id = query.user_id
self.queries << new_query self.queries << new_query
end end
end end
+5
View File
@@ -43,6 +43,11 @@ class Version < ActiveRecord::Base
user.allowed_to?(:view_issues, self.project) user.allowed_to?(:view_issues, self.project)
end end
# Version files have same visibility as project files
def attachments_visible?(*args)
project.present? && project.attachments_visible?(*args)
end
def start_date def start_date
@start_date ||= fixed_issues.minimum('start_date') @start_date ||= fixed_issues.minimum('start_date')
end end
@@ -15,13 +15,13 @@
<ul> <ul>
<% @activities.each do |u| -%> <% @activities.each do |u| -%>
<li><%= context_menu_link u.name, {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post, <li><%= context_menu_link u.name, {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post,
:selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:update] %></li> :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %></li>
<% end -%> <% end -%>
<li><%= context_menu_link l(:label_nobody), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post, <li><%= context_menu_link l(:label_nobody), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post,
:selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:update] %></li> :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %></li>
</ul> </ul>
</li> </li>
<% end %> <% end %>
<%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %> <%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %>
+1 -1
View File
@@ -2,5 +2,5 @@
<p><em><%= format_time(document.updated_on) %></em></p> <p><em><%= format_time(document.updated_on) %></em></p>
<div class="wiki"> <div class="wiki">
<%= textilizable(truncate_lines(document.description)) %> <%= textilizable(truncate_lines(document.description), :object => document) %>
</div> </div>
+1 -1
View File
@@ -15,7 +15,7 @@
<%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %> <%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %>
</fieldset> </fieldset>
<% end %> <% end %>
<% if authorize_for('timelog', 'edit') %> <% if User.current.allowed_to?(:log_time, @project) %>
<fieldset class="tabular"><legend><%= l(:button_log_time) %></legend> <fieldset class="tabular"><legend><%= l(:button_log_time) %></legend>
<% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %> <% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
<div class="splitcontentleft"> <div class="splitcontentleft">
@@ -32,6 +32,7 @@
</div> </div>
<% unless @hours.empty? %> <% unless @hours.empty? %>
<div class="autoscroll">
<table class="list" id="time-report"> <table class="list" id="time-report">
<thead> <thead>
<tr> <tr>
@@ -59,6 +60,7 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div>
<% other_formats_links do |f| %> <% other_formats_links do |f| %>
<%= f.link_to 'CSV', :url => params %> <%= f.link_to 'CSV', :url => params %>
+2
View File
@@ -1,5 +1,6 @@
<% form_tag({}) do -%> <% form_tag({}) do -%>
<%= hidden_field_tag 'back_url', url_for(params) %> <%= hidden_field_tag 'back_url', url_for(params) %>
<div class="autoscroll">
<table class="list time-entries"> <table class="list time-entries">
<thead> <thead>
<tr> <tr>
@@ -48,6 +49,7 @@
<% end -%> <% end -%>
</tbody> </tbody>
</table> </table>
</div>
<% end -%> <% end -%>
<%= context_menu time_entries_context_menu_path %> <%= context_menu time_entries_context_menu_path %>
+1 -1
View File
@@ -6,7 +6,7 @@
<h2><%= @page.pretty_title %></h2> <h2><%= @page.pretty_title %></h2>
<p> <p>
<%= l(:label_version) %> <%= link_to @annotate.content.version, :action => 'show', :id => @page.title, :version => @annotate.content.version %> <%= l(:label_version) %> <%= link_to @annotate.content.version, :action => 'show', :project_id => @project, :id => @page.title, :version => @annotate.content.version %>
<em>(<%= @annotate.content.author ? @annotate.content.author.name : "anonyme" %>, <%= format_time(@annotate.content.updated_on) %>)</em> <em>(<%= @annotate.content.author ? @annotate.content.author.name : "anonyme" %>, <%= format_time(@annotate.content.updated_on) %>)</em>
</p> </p>
+2 -2
View File
@@ -46,8 +46,8 @@
<% end %> <% end %>
<% other_formats_links do |f| %> <% other_formats_links do |f| %>
<%= f.link_to 'HTML', :url => {:id => @page.title, :version => @content.version} %> <%= f.link_to 'HTML', :url => {:id => @page.title, :version => params[:version]} %>
<%= f.link_to 'TXT', :url => {:id => @page.title, :version => @content.version} %> <%= f.link_to 'TXT', :url => {:id => @page.title, :version => params[:version]} %>
<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> <% end if User.current.allowed_to?(:export_wiki_pages, @project) %>
<% content_for :header_tags do %> <% content_for :header_tags do %>
+1 -1
View File
@@ -368,7 +368,7 @@ bg:
setting_issue_done_ratio_issue_status: Използване на състоянието на задачите setting_issue_done_ratio_issue_status: Използване на състоянието на задачите
setting_start_of_week: Първи ден на седмицата setting_start_of_week: Първи ден на седмицата
setting_rest_api_enabled: Разрешаване на REST web сървис setting_rest_api_enabled: Разрешаване на REST web сървис
setting_cache_formatted_text: Cache formatted text setting_cache_formatted_text: Кещиране на форматираните текстове
setting_default_notification_option: Подразбиращ се начин за известяване setting_default_notification_option: Подразбиращ се начин за известяване
setting_commit_logtime_enabled: Разрешаване на отчитането на работното време setting_commit_logtime_enabled: Разрешаване на отчитането на работното време
setting_commit_logtime_activity_id: Дейност при отчитане на работното време setting_commit_logtime_activity_id: Дейност при отчитане на работното време
+61 -60
View File
@@ -1,4 +1,4 @@
# Chinese (China) translations for Ruby on Rails # Chinese (China) translations for Ruby on Rails
# by tsechingho (http://github.com/tsechingho) # by tsechingho (http://github.com/tsechingho)
zh: zh:
# Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl)
@@ -11,7 +11,7 @@ zh:
default: "%Y-%m-%d" default: "%Y-%m-%d"
short: "%b%d日" short: "%b%d日"
long: "%Y年%b%d日" long: "%Y年%b%d日"
day_names: [星期天, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六] day_names: [星期天, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六]
abbr_day_names: [日, 一, 二, 三, 四, 五, 六] abbr_day_names: [日, 一, 二, 三, 四, 五, 六]
@@ -73,7 +73,7 @@ zh:
number: number:
# Default format for numbers # Default format for numbers
format: format:
separator: "." separator: "."
delimiter: "" delimiter: ""
precision: 3 precision: 3
human: human:
@@ -91,13 +91,12 @@ zh:
gb: "GB" gb: "GB"
tb: "TB" tb: "TB"
# Used in array.to_sentence. # Used in array.to_sentence.
support: support:
array: array:
sentence_connector: "和" sentence_connector: "和"
skip_last_comma: false skip_last_comma: false
activerecord: activerecord:
errors: errors:
template: template:
@@ -131,7 +130,7 @@ zh:
cant_link_an_issue_with_a_descendant: "问题不能关联到它的子任务" cant_link_an_issue_with_a_descendant: "问题不能关联到它的子任务"
actionview_instancetag_blank_option: 请选择 actionview_instancetag_blank_option: 请选择
general_text_No: '否' general_text_No: '否'
general_text_Yes: '是' general_text_Yes: '是'
general_text_no: '否' general_text_no: '否'
@@ -142,7 +141,7 @@ zh:
general_csv_encoding: gb18030 general_csv_encoding: gb18030
general_pdf_encoding: gb18030 general_pdf_encoding: gb18030
general_first_day_of_week: '7' general_first_day_of_week: '7'
notice_account_updated: 帐号更新成功 notice_account_updated: 帐号更新成功
notice_account_invalid_creditentials: 无效的用户名或密码 notice_account_invalid_creditentials: 无效的用户名或密码
notice_account_password_updated: 密码更新成功 notice_account_password_updated: 密码更新成功
@@ -173,7 +172,7 @@ zh:
notice_unable_delete_time_entry: 无法删除工时 notice_unable_delete_time_entry: 无法删除工时
notice_issue_done_ratios_updated: 问题完成度已更新。 notice_issue_done_ratios_updated: 问题完成度已更新。
notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})"
error_can_t_load_default_data: "无法载入默认设置:%{value}" error_can_t_load_default_data: "无法载入默认设置:%{value}"
error_scm_not_found: "版本库中不存在该条目和(或)其修订版本。" error_scm_not_found: "版本库中不存在该条目和(或)其修订版本。"
error_scm_command_failed: "访问版本库时发生错误:%{value}" error_scm_command_failed: "访问版本库时发生错误:%{value}"
@@ -192,7 +191,7 @@ zh:
error_unable_delete_issue_status: '无法删除问题状态' error_unable_delete_issue_status: '无法删除问题状态'
error_unable_to_connect: "无法连接 (%{value})" error_unable_to_connect: "无法连接 (%{value})"
warning_attachments_not_saved: "%{count} 个文件保存失败" warning_attachments_not_saved: "%{count} 个文件保存失败"
mail_subject_lost_password: "您的 %{value} 密码" mail_subject_lost_password: "您的 %{value} 密码"
mail_body_lost_password: '请点击以下链接来修改您的密码:' mail_body_lost_password: '请点击以下链接来修改您的密码:'
mail_subject_register: "%{value}帐号激活" mail_subject_register: "%{value}帐号激活"
@@ -207,10 +206,10 @@ zh:
mail_body_wiki_content_added: "'%{id}' wiki页面已由 %{author} 添加。" mail_body_wiki_content_added: "'%{id}' wiki页面已由 %{author} 添加。"
mail_subject_wiki_content_updated: "'%{id}' wiki页面已更新。" mail_subject_wiki_content_updated: "'%{id}' wiki页面已更新。"
mail_body_wiki_content_updated: "'%{id}' wiki页面已由 %{author} 更新。" mail_body_wiki_content_updated: "'%{id}' wiki页面已由 %{author} 更新。"
gui_validation_error: 1 个错误 gui_validation_error: 1 个错误
gui_validation_error_plural: "%{count} 个错误" gui_validation_error_plural: "%{count} 个错误"
field_name: 名称 field_name: 名称
field_description: 描述 field_description: 描述
field_summary: 摘要 field_summary: 摘要
@@ -241,7 +240,7 @@ zh:
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: 目标版本
@@ -273,7 +272,7 @@ zh:
field_attr_mail: 邮件属性 field_attr_mail: 邮件属性
field_onthefly: 即时用户生成 field_onthefly: 即时用户生成
field_start_date: 开始日期 field_start_date: 开始日期
field_done_ratio: % 完成 field_done_ratio: "% 完成"
field_auth_source: 认证模式 field_auth_source: 认证模式
field_hide_mail: 隐藏我的邮件地址 field_hide_mail: 隐藏我的邮件地址
field_comments: 注释 field_comments: 注释
@@ -308,7 +307,7 @@ zh:
field_assigned_to_role: 角色的成员 field_assigned_to_role: 角色的成员
field_text: 文本字段 field_text: 文本字段
field_visible: 可见的 field_visible: 可见的
setting_app_title: 应用程序标题 setting_app_title: 应用程序标题
setting_app_subtitle: 应用程序子标题 setting_app_subtitle: 应用程序子标题
setting_welcome_text: 欢迎文字 setting_welcome_text: 欢迎文字
@@ -366,7 +365,7 @@ zh:
setting_commit_logtime_enabled: 激活时间日志 setting_commit_logtime_enabled: 激活时间日志
setting_commit_logtime_activity_id: 记录的活动 setting_commit_logtime_activity_id: 记录的活动
setting_gantt_items_limit: 在甘特图上显示的最大记录数 setting_gantt_items_limit: 在甘特图上显示的最大记录数
permission_add_project: 新建项目 permission_add_project: 新建项目
permission_add_subprojects: 新建子项目 permission_add_subprojects: 新建子项目
permission_edit_project: 编辑项目 permission_edit_project: 编辑项目
@@ -402,7 +401,7 @@ zh:
permission_manage_files: 管理文件 permission_manage_files: 管理文件
permission_view_files: 查看文件 permission_view_files: 查看文件
permission_manage_wiki: 管理Wiki permission_manage_wiki: 管理Wiki
permission_rename_wiki_pages: 重命名Wiki页面 permission_rename_wiki_pages: 定向/重命名Wiki页面
permission_delete_wiki_pages: 删除Wiki页面 permission_delete_wiki_pages: 删除Wiki页面
permission_view_wiki_pages: 查看Wiki permission_view_wiki_pages: 查看Wiki
permission_view_wiki_edits: 查看Wiki历史记录 permission_view_wiki_edits: 查看Wiki历史记录
@@ -422,7 +421,7 @@ zh:
permission_delete_own_messages: 删除自己的帖子 permission_delete_own_messages: 删除自己的帖子
permission_export_wiki_pages: 导出 wiki 页面 permission_export_wiki_pages: 导出 wiki 页面
permission_manage_subtasks: 管理子任务 permission_manage_subtasks: 管理子任务
project_module_issue_tracking: 问题跟踪 project_module_issue_tracking: 问题跟踪
project_module_time_tracking: 时间跟踪 project_module_time_tracking: 时间跟踪
project_module_news: 新闻 project_module_news: 新闻
@@ -433,7 +432,7 @@ zh:
project_module_boards: 讨论区 project_module_boards: 讨论区
project_module_calendar: 日历 project_module_calendar: 日历
project_module_gantt: 甘特图 project_module_gantt: 甘特图
label_user: 用户 label_user: 用户
label_user_plural: 用户 label_user_plural: 用户
label_user_new: 新建用户 label_user_new: 新建用户
@@ -797,7 +796,7 @@ zh:
label_project_copy_notifications: 复制项目时发送邮件通知 label_project_copy_notifications: 复制项目时发送邮件通知
label_principal_search: "搜索用户或组:" label_principal_search: "搜索用户或组:"
label_user_search: "搜索用户:" label_user_search: "搜索用户:"
button_login: 登录 button_login: 登录
button_submit: 提交 button_submit: 提交
button_save: 保存 button_save: 保存
@@ -832,7 +831,7 @@ zh:
button_archive: 存档 button_archive: 存档
button_unarchive: 取消存档 button_unarchive: 取消存档
button_reset: 重置 button_reset: 重置
button_rename: 重命名 button_rename: 重命名/重定向
button_change_password: 修改密码 button_change_password: 修改密码
button_copy: 复制 button_copy: 复制
button_copy_and_follow: 复制并转到新问题 button_copy_and_follow: 复制并转到新问题
@@ -846,13 +845,13 @@ zh:
status_active: 活动的 status_active: 活动的
status_registered: 已注册 status_registered: 已注册
status_locked: 已锁定 status_locked: 已锁定
version_status_open: 打开 version_status_open: 打开
version_status_locked: 锁定 version_status_locked: 锁定
version_status_closed: 关闭 version_status_closed: 关闭
field_active: 活动 field_active: 活动
text_select_mail_notifications: 选择需要发送邮件通知的动作 text_select_mail_notifications: 选择需要发送邮件通知的动作
text_regexp_info: 例如:^[A-Z0-9]+$ text_regexp_info: 例如:^[A-Z0-9]+$
text_min_max_length_info: 0 表示没有限制 text_min_max_length_info: 0 表示没有限制
@@ -910,9 +909,9 @@ zh:
text_wiki_page_destroy_children: 删除子页面及其所有下级页面 text_wiki_page_destroy_children: 删除子页面及其所有下级页面
text_wiki_page_reassign_children: 将子页面的上级页面设置为 text_wiki_page_reassign_children: 将子页面的上级页面设置为
text_own_membership_delete_confirmation: 你正在删除你现有的某些或全部权限,如果这样做了你可能将会再也无法编辑该项目了。你确定要继续吗? text_own_membership_delete_confirmation: 你正在删除你现有的某些或全部权限,如果这样做了你可能将会再也无法编辑该项目了。你确定要继续吗?
text_zoom_in: Zoom in text_zoom_in: 放大
text_zoom_out: Zoom out text_zoom_out: 缩小
default_role_manager: 管理人员 default_role_manager: 管理人员
default_role_developer: 开发人员 default_role_developer: 开发人员
default_role_reporter: 报告人员 default_role_reporter: 报告人员
@@ -934,48 +933,50 @@ zh:
default_priority_immediate: 立刻 default_priority_immediate: 立刻
default_activity_design: 设计 default_activity_design: 设计
default_activity_development: 开发 default_activity_development: 开发
enumeration_issue_priorities: 问题优先级 enumeration_issue_priorities: 问题优先级
enumeration_doc_categories: 文档类别 enumeration_doc_categories: 文档类别
enumeration_activities: 活动(时间跟踪) enumeration_activities: 活动(时间跟踪)
enumeration_system_activity: 系统活动 enumeration_system_activity: 系统活动
field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text field_warn_on_leaving_unsaved: 当离开未保存内容的页面时,提示我
text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. text_warn_on_leaving_unsaved: 若离开当前页面,则该页面内未保存的内容将丢失。
label_my_queries: My custom queries label_my_queries: 我的自定义查询
text_journal_changed_no_detail: "%{label} updated" text_journal_changed_no_detail: "%{label} 已更新。"
label_news_comment_added: Comment added to a news label_news_comment_added: 添加到新闻的评论
button_expand_all: Expand all button_expand_all: 展开所有
button_collapse_all: Collapse all button_collapse_all: 合拢所有
label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_assignee: 当用户是问题的分配对象时所允许的问题状态转换
label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author label_additional_workflow_transitions_for_author: 当用户是问题作者时所允许的问题状态转换
label_bulk_edit_selected_time_entries: Bulk edit selected time entries label_bulk_edit_selected_time_entries: 批量修改选定的时间条目
text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? text_time_entries_destroy_confirmation: 是否确定要删除选定的时间条目?
label_role_anonymous: Anonymous label_role_anonymous: Anonymous
label_role_non_member: Non member label_role_non_member: Non member
label_issue_note_added: Note added label_issue_note_added: 问题备注已添加
label_issue_status_updated: Status updated label_issue_status_updated: 问题状态更新
label_issue_priority_updated: Priority updated label_issue_priority_updated: 问题优先级更新
label_issues_visibility_own: Issues created by or assigned to the user label_issues_visibility_own: 创建或分配给用户的问题
field_issues_visibility: Issues visibility field_issues_visibility: 问题可见
label_issues_visibility_all: All issues label_issues_visibility_all: 全部问题
permission_set_own_issues_private: Set own issues public or private permission_set_own_issues_private: 设置自己的问题为公开或私有
field_is_private: Private field_is_private: 私有
permission_set_issues_private: Set issues public or private permission_set_issues_private: 设置问题为公开或私有
label_issues_visibility_public: All non private issues label_issues_visibility_public: 全部非私有问题
text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). text_issues_destroy_descendants_confirmation: 此操作同时会删除 %{count} 个子任务。
field_commit_logs_encoding: 提交注释的编码 field_commit_logs_encoding: 提交注释的编码
field_scm_path_encoding: Path encoding field_scm_path_encoding: 路径编码
text_scm_path_encoding_note: "Default: UTF-8" text_scm_path_encoding_note: "默认: UTF-8"
field_path_to_repository: Path to repository field_path_to_repository: 库路径
field_root_directory: Root directory field_root_directory: 根目录
field_cvs_module: Module field_cvs_module: CVS Module
field_cvsroot: CVSROOT field_cvsroot: CVSROOT
text_git_repository_note: Bare and local repository (e.g. /gitrepo, c:\gitrepo) text_mercurial_repository_note: 本地库 (e.g. /hgrepo, c:\hgrepo)
text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) text_scm_command: 命令
text_scm_command: Command text_scm_command_version: 版本
text_scm_command_version: Version label_git_report_last_commit: 报告最后一次文件/目录提交
label_git_report_last_commit: Report last commit for files and directories text_scm_config: 您可以在config/configuration.yml中配置您的SCM命令。 请在编辑后,重启Redmine应用。
text_scm_config: You can configure your scm commands in config/configuration.yml. Please restart the application after editing it. text_scm_command_not_available: Scm命令不可用。 请检查管理面板的配置。
text_scm_command_not_available: Scm command is not available. Please check settings on the administration panel.
text_git_repository_note: 库中无内容。(e.g. /gitrepo, c:\gitrepo)
+21
View File
@@ -4,6 +4,27 @@ Redmine - project management software
Copyright (C) 2006-2011 Jean-Philippe Lang Copyright (C) 2006-2011 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2011-12-10 v1.2.3
* Defect #8707: Reposman: wrong constant name
* Defect #8809: Table in timelog report overflows
* Defect #9055: Version files in Files module cannot be downloaded if issue tracking is disabled
* Defect #9137: db:encrypt fails to handle repositories with blank password
* Defect #9394: Custom date field only validating on regex and not a valid date
* Defect #9405: Any user with :log_time permission can edit time entries via context menu
* Defect #9448: The attached images are not shown in documents
* Defect #9520: Copied private query not visible after project copy
* Defect #9552: Error when reading ciphered text from the database without cipher key configured
* Defect #9566: Redmine.pm considers all projects private when login_required is enabled
* Defect #9567: Redmine.pm potential security issue with cache credential enabled and subversion
* Defect #9577: Deleting a subtasks doesn't update parent's rgt & lft values
* Defect #9597: Broken version links in wiki annotate history
* Defect #9682: Wiki HTML Export only useful when Access history is accessible
* Defect #9737: Custom values deleted before issue submit
* Defect #9741: calendar-hr.js (Croatian) is not UTF-8
* Patch #9558: Simplified Chinese translation for 1.2.2 updated
* Patch #9695: Bulgarian translation (r7942)
== 2011-11-11 v1.2.2 == 2011-11-11 v1.2.2
* Defect #3276: Incorrect handling of anchors in Wiki to HTML export * Defect #3276: Incorrect handling of anchors in Wiki to HTML export
+15 -12
View File
@@ -149,15 +149,16 @@ sub RedmineDSN {
$self->{RedmineDSN} = $arg; $self->{RedmineDSN} = $arg;
my $query = "SELECT my $query = "SELECT
hashed_password, salt, auth_source_id, permissions hashed_password, salt, auth_source_id, permissions
FROM members, projects, users, roles, member_roles FROM projects, users, roles
WHERE WHERE
projects.id=members.project_id users.login=?
AND member_roles.member_id=members.id AND projects.identifier=?
AND users.id=members.user_id
AND roles.id=member_roles.role_id
AND users.status=1 AND users.status=1
AND login=? AND (
AND identifier=? "; roles.id IN (SELECT member_roles.role_id FROM members, member_roles WHERE members.user_id = users.id AND members.project_id = projects.id AND members.id = member_roles.member_id)
OR
(roles.builtin=1 AND cast(projects.is_public as CHAR) IN ('t', '1'))
) ";
$self->{RedmineQuery} = trim($query); $self->{RedmineQuery} = trim($query);
} }
@@ -327,11 +328,13 @@ sub is_member {
my $project_id = get_project_identifier($r); my $project_id = get_project_identifier($r);
my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass); my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
my $access_mode = defined $read_only_methods{$r->method} ? "R" : "W";
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config); my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
my $usrprojpass; my $usrprojpass;
if ($cfg->{RedmineCacheCredsMax}) { if ($cfg->{RedmineCacheCredsMax}) {
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id); $usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest)); return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
} }
my $query = $cfg->{RedmineQuery}; my $query = $cfg->{RedmineQuery};
@@ -344,7 +347,7 @@ sub is_member {
unless ($auth_source_id) { unless ($auth_source_id) {
my $method = $r->method; my $method = $r->method;
my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest); my $salted_password = Digest::SHA1::sha1_hex($salt.$pass_digest);
if ($hashed_password eq $salted_password && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) { if ($hashed_password eq $salted_password && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/) ) {
$ret = 1; $ret = 1;
last; last;
} }
@@ -363,7 +366,7 @@ sub is_member {
filter => "(".$rowldap[6]."=%s)" filter => "(".$rowldap[6]."=%s)"
); );
my $method = $r->method; my $method = $r->method;
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && ((defined $read_only_methods{$method} && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/)); $ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass) && (($access_mode eq "R" && $permissions =~ /:browse_repository/) || $permissions =~ /:commit_access/));
} }
$sthldap->finish(); $sthldap->finish();
@@ -377,10 +380,10 @@ sub is_member {
if ($cfg->{RedmineCacheCredsMax} and $ret) { if ($cfg->{RedmineCacheCredsMax} and $ret) {
if (defined $usrprojpass) { if (defined $usrprojpass) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
} else { } else {
if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) { if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest); $cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
$cfg->{RedmineCacheCredsCount}++; $cfg->{RedmineCacheCredsCount}++;
} else { } else {
$cfg->{RedmineCacheCreds}->clear(); $cfg->{RedmineCacheCreds}->clear();
+3 -3
View File
@@ -88,10 +88,10 @@ Redmine::AccessControl.map do |map|
end end
map.project_module :time_tracking do |map| map.project_module :time_tracking do |map|
map.permission :log_time, {:timelog => [:new, :create, :edit, :update, :bulk_edit, :bulk_update]}, :require => :loggedin map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
map.permission :view_time_entries, :timelog => [:index, :show], :time_entry_reports => [:report] map.permission :view_time_entries, :timelog => [:index, :show], :time_entry_reports => [:report]
map.permission :edit_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member
map.permission :edit_own_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin
map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
end end
+9 -1
View File
@@ -23,7 +23,7 @@ module Redmine
class << self class << self
def encrypt_text(text) def encrypt_text(text)
if cipher_key.blank? if cipher_key.blank? || text.blank?
text text
else else
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
@@ -39,6 +39,10 @@ module Redmine
def decrypt_text(text) def decrypt_text(text)
if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/) if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/)
if cipher_key.blank?
logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger
return text
end
text = match[1] text = match[1]
c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") c = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
e, iv = text.split("--").map {|s| Base64.decode64(s)} e, iv = text.split("--").map {|s| Base64.decode64(s)}
@@ -56,6 +60,10 @@ module Redmine
key = Redmine::Configuration['database_cipher_key'].to_s key = Redmine::Configuration['database_cipher_key'].to_s
key.blank? ? nil : Digest::SHA256.hexdigest(key) key.blank? ? nil : Digest::SHA256.hexdigest(key)
end end
def logger
RAILS_DEFAULT_LOGGER
end
end end
module ClassMethods module ClassMethods
+1 -1
View File
@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc: module VERSION #:nodoc:
MAJOR = 1 MAJOR = 1
MINOR = 2 MINOR = 2
TINY = 2 TINY = 3
# Branch values: # Branch values:
# * official release: nil # * official release: nil
@@ -18,7 +18,7 @@ Calendar._DN = new Array
"Cetvrtak", "Cetvrtak",
"Petak", "Petak",
"Subota", "Subota",
"Nedjelja"); "Nedjelja");
// Please note that the following array of short day names (and the same goes // Please note that the following array of short day names (and the same goes
// for short month names, _SMN) isn't absolutely necessary. We give it here // for short month names, _SMN) isn't absolutely necessary. We give it here
@@ -51,7 +51,7 @@ Calendar._FD = 0;
Calendar._MN = new Array Calendar._MN = new Array
("Sijecanj", ("Sijecanj",
"Veljaca", "Veljaca",
"Ožujak", "Ožujak",
"Travanj", "Travanj",
"Svibanj", "Svibanj",
"Lipanj", "Lipanj",
@@ -66,7 +66,7 @@ Calendar._MN = new Array
Calendar._SMN = new Array Calendar._SMN = new Array
("Sij", ("Sij",
"Velj", "Velj",
"Ožu", "Ožu",
"Tra", "Tra",
"Svi", "Svi",
"Lip", "Lip",
@@ -100,7 +100,7 @@ Calendar._TT["ABOUT_TIME"] = "\n\n" +
Calendar._TT["PREV_YEAR"] = "Prethodna godina (hold for menu)"; Calendar._TT["PREV_YEAR"] = "Prethodna godina (hold for menu)";
Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Prethodni mjesec (hold for menu)";
Calendar._TT["GO_TODAY"] = "Na današnji dan"; Calendar._TT["GO_TODAY"] = "Na današnji dan";
Calendar._TT["NEXT_MONTH"] = "Naredni mjesec (hold for menu)"; Calendar._TT["NEXT_MONTH"] = "Naredni mjesec (hold for menu)";
Calendar._TT["NEXT_YEAR"] = "Naredna godina (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Naredna godina (hold for menu)";
Calendar._TT["SEL_DATE"] = "Odaberite datum"; Calendar._TT["SEL_DATE"] = "Odaberite datum";
@@ -109,7 +109,7 @@ Calendar._TT["PART_TODAY"] = " (Danas)";
// the following is to inform that "%s" is to be the first day of week // the following is to inform that "%s" is to be the first day of week
// %s will be replaced with the day name. // %s will be replaced with the day name.
Calendar._TT["DAY_FIRST"] = "Prikaži %s prvo"; Calendar._TT["DAY_FIRST"] = "Prikaži %s prvo";
// This may be locale-dependent. It specifies the week-end days, as an array // This may be locale-dependent. It specifies the week-end days, as an array
// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1
+1 -1
View File
@@ -102,7 +102,7 @@ attachments_009:
container_type: Version container_type: Version
container_id: 1 container_id: 1
downloads: 0 downloads: 0
disk_filename: 060719210727_version_file.zip disk_filename: 060719210727_archive.zip
digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 digest: b91e08d0cf966d5c6ff411bd8c4cc3a2
id: 9 id: 9
filesize: 452 filesize: 452
+15 -2
View File
@@ -104,6 +104,12 @@ class AttachmentsControllerTest < ActionController::TestCase
assert_equal 'application/x-ruby', @response.content_type assert_equal 'application/x-ruby', @response.content_type
end end
def test_download_version_file_with_issue_tracking_disabled
Project.find(1).disable_module! :issue_tracking
get :download, :id => 9
assert_response :success
end
def test_download_should_assign_content_type_if_blank def test_download_should_assign_content_type_if_blank
Attachment.find(4).update_attribute(:content_type, '') Attachment.find(4).update_attribute(:content_type, '')
@@ -123,6 +129,7 @@ class AttachmentsControllerTest < ActionController::TestCase
end end
def test_destroy_issue_attachment def test_destroy_issue_attachment
set_tmp_attachments_directory
issue = Issue.find(3) issue = Issue.find(3)
@request.session[:user_id] = 2 @request.session[:user_id] = 2
@@ -139,6 +146,7 @@ class AttachmentsControllerTest < ActionController::TestCase
end end
def test_destroy_wiki_page_attachment def test_destroy_wiki_page_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2 @request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do assert_difference 'Attachment.count', -1 do
post :destroy, :id => 3 post :destroy, :id => 3
@@ -147,6 +155,7 @@ class AttachmentsControllerTest < ActionController::TestCase
end end
def test_destroy_project_attachment def test_destroy_project_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2 @request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do assert_difference 'Attachment.count', -1 do
post :destroy, :id => 8 post :destroy, :id => 8
@@ -155,6 +164,7 @@ class AttachmentsControllerTest < ActionController::TestCase
end end
def test_destroy_version_attachment def test_destroy_version_attachment
set_tmp_attachments_directory
@request.session[:user_id] = 2 @request.session[:user_id] = 2
assert_difference 'Attachment.count', -1 do assert_difference 'Attachment.count', -1 do
post :destroy, :id => 9 post :destroy, :id => 9
@@ -163,8 +173,11 @@ class AttachmentsControllerTest < ActionController::TestCase
end end
def test_destroy_without_permission def test_destroy_without_permission
post :destroy, :id => 3 set_tmp_attachments_directory
assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3' assert_no_difference 'Attachment.count' do
delete :destroy, :id => 3
end
assert_response 302
assert Attachment.find_by_id(3) assert Attachment.find_by_id(3)
end end
end end
@@ -115,4 +115,23 @@ class ContextMenusControllerTest < ActionController::TestCase
assert_template 'context_menu' assert_template 'context_menu'
assert_equal [1], assigns(:issues).collect(&:id) assert_equal [1], assigns(:issues).collect(&:id)
end end
def test_time_entries_context_menu
@request.session[:user_id] = 2
get :time_entries, :ids => [1, 2]
assert_response :success
assert_template 'time_entries'
assert_tag 'a', :content => 'Edit'
assert_no_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
end
def test_time_entries_context_menu_without_edit_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :edit_time_entries
get :time_entries, :ids => [1, 2]
assert_response :success
assert_template 'time_entries'
assert_tag 'a', :content => 'Edit', :attributes => {:class => /disabled/}
end
end end
+16
View File
@@ -872,6 +872,22 @@ class IssuesControllerTest < ActionController::TestCase
assert_equal Issue.find(1), assigns(:issue) assert_equal Issue.find(1), assigns(:issue)
end end
def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
get :edit, :id => 1
assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
end
def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :log_time
get :edit, :id => 1
assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
end
def test_get_edit_with_params def test_get_edit_with_params
@request.session[:user_id] = 2 @request.session[:user_id] = 2
get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 }, get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 },
+13 -1
View File
@@ -39,7 +39,10 @@ class SysControllerTest < ActionController::TestCase
assert_equal 'application/xml', @response.content_type assert_equal 'application/xml', @response.content_type
with_options :tag => 'projects' do |test| with_options :tag => 'projects' do |test|
test.assert_tag :children => { :count => Project.active.has_module(:repository).count } test.assert_tag :children => { :count => Project.active.has_module(:repository).count }
test.assert_tag 'project', :child => {:tag => 'identifier', :sibling => {:tag => 'is-public'}}
end end
assert_no_tag 'extra-info'
assert_no_tag 'extra_info'
end end
def test_create_project_repository def test_create_project_repository
@@ -49,10 +52,19 @@ class SysControllerTest < ActionController::TestCase
:vendor => 'Subversion', :vendor => 'Subversion',
:repository => { :url => 'file:///create/project/repository/subproject2'} :repository => { :url => 'file:///create/project/repository/subproject2'}
assert_response :created assert_response :created
assert_equal 'application/xml', @response.content_type
r = Project.find(4).repository r = Project.find(4).repository
assert r.is_a?(Repository::Subversion) assert r.is_a?(Repository::Subversion)
assert_equal 'file:///create/project/repository/subproject2', r.url assert_equal 'file:///create/project/repository/subproject2', r.url
assert_tag 'repository-subversion',
:child => {
:tag => 'id', :content => r.id.to_s,
:sibling => {:tag => 'url', :content => r.url}
}
assert_no_tag 'extra-info'
assert_no_tag 'extra_info'
end end
def test_fetch_changesets def test_fetch_changesets
@@ -115,6 +115,18 @@ class TimelogControllerTest < ActionController::TestCase
assert_equal 3, t.user_id assert_equal 3, t.user_id
end end
def test_create_without_log_time_permission_should_be_denied
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :log_time
post :create, :project_id => 1,
:time_entry => {:activity_id => '11',
:issue_id => '',
:spent_on => '2008-03-14',
:hours => '7.3'}
assert_response 403
end
def test_update def test_update
entry = TimeEntry.find(1) entry = TimeEntry.find(1)
assert_equal 1, entry.issue_id assert_equal 1, entry.issue_id
@@ -161,6 +173,9 @@ class TimelogControllerTest < ActionController::TestCase
def test_bulk_update_on_different_projects def test_bulk_update_on_different_projects
@request.session[:user_id] = 2 @request.session[:user_id] = 2
# makes user a manager on the other project
Member.create!(:user_id => 2, :project_id => 3, :role_ids => [1])
# update time entry activity # update time entry activity
post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 } post :bulk_update, :ids => [1, 2, 4], :time_entry => { :activity_id => 9 }
@@ -203,6 +218,14 @@ class TimelogControllerTest < ActionController::TestCase
assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier assert_redirected_to :controller => 'timelog', :action => 'index', :project_id => Project.find(1).identifier
end end
def test_post_bulk_update_without_edit_permission_should_be_denied
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :edit_time_entries
post :bulk_update, :ids => [1,2]
assert_response 403
end
def test_destroy def test_destroy
@request.session[:user_id] = 2 @request.session[:user_id] = 2
delete :destroy, :id => 1 delete :destroy, :id => 1
+7
View File
@@ -43,6 +43,13 @@ class WikiControllerTest < ActionController::TestCase
:child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' },
:content => 'Page with an inline image' } } :content => 'Page with an inline image' } }
end end
def test_export_link
Role.anonymous.add_permission! :export_wiki_pages
get :show, :project_id => 'ecookbook'
assert_response :success
assert_tag 'a', :attributes => {:href => '/projects/ecookbook/wiki/CookBook_documentation.txt'}
end
def test_show_page_with_name def test_show_page_with_name
get :show, :project_id => 1, :id => 'Another_page' get :show, :project_id => 1, :id => 'Another_page'
+2
View File
@@ -64,6 +64,8 @@ class CustomValueTest < ActiveSupport::TestCase
assert v.valid? assert v.valid?
v.value = 'abc' v.value = 'abc'
assert !v.valid? assert !v.valid?
v.value = '1975-07-33'
assert !v.valid?
v.value = '1975-07-14' v.value = '1975-07-14'
assert v.valid? assert v.valid?
end end
+14
View File
@@ -222,6 +222,20 @@ class IssueNestedSetTest < ActiveSupport::TestCase
assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt] assert_equal [issue1.id, 1, 4], [issue1.root_id, issue1.lft, issue1.rgt]
assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt] assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt]
end end
def test_destroy_child_should_update_parent
issue = create_issue!
child1 = create_issue!(:parent_issue_id => issue.id)
child2 = create_issue!(:parent_issue_id => issue.id)
issue.reload
assert_equal [issue.id, 1, 6], [issue.root_id, issue.lft, issue.rgt]
child2.reload.destroy
issue.reload
assert_equal [issue.id, 1, 4], [issue.root_id, issue.lft, issue.rgt]
end
def test_destroy_parent_issue_updated_during_children_destroy def test_destroy_parent_issue_updated_during_children_destroy
parent = create_issue! parent = create_issue!
+16
View File
@@ -232,6 +232,22 @@ class IssueTest < ActiveSupport::TestCase
assert_equal custom_value.id, issue.custom_value_for(field).id assert_equal custom_value.id, issue.custom_value_for(field).id
end end
def test_should_not_update_custom_fields_on_changing_tracker_with_different_custom_fields
issue = Issue.new(:project_id => 1)
issue.attributes = {:tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'Test', :custom_field_values => {'2' => 'Test'}}
issue.save!
assert !Tracker.find(2).custom_field_ids.include?(2)
issue = Issue.find(issue.id)
issue.attributes = {:tracker_id => 2, :custom_field_values => {'1' => ''}}
issue = Issue.find(issue.id)
custom_value = issue.custom_value_for(2)
assert_not_nil custom_value
assert_equal 'Test', custom_value.value
end
def test_assigning_tracker_id_should_reload_custom_fields_values def test_assigning_tracker_id_should_reload_custom_fields_values
issue = Issue.new(:project => Project.find(1)) issue = Issue.new(:project => Project.find(1))
assert issue.custom_field_values.empty? assert issue.custom_field_values.empty?
+23 -1
View File
@@ -43,6 +43,14 @@ class Redmine::CipheringTest < ActiveSupport::TestCase
end end
end end
def test_blank_password_should_be_clear
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository::Subversion.generate!(:password => '')
assert_equal '', r.password
assert_equal '', r.read_attribute(:password)
end
end
def test_unciphered_password_should_be_readable def test_unciphered_password_should_be_readable
Redmine::Configuration.with 'database_cipher_key' => nil do Redmine::Configuration.with 'database_cipher_key' => nil do
r = Repository::Subversion.generate!(:password => 'clear') r = Repository::Subversion.generate!(:password => 'clear')
@@ -53,7 +61,21 @@ class Redmine::CipheringTest < ActiveSupport::TestCase
assert_equal 'clear', r.password assert_equal 'clear', r.password
end end
end end
def test_ciphered_password_with_no_cipher_key_configured_should_be_returned_ciphered
Redmine::Configuration.with 'database_cipher_key' => 'secret' do
r = Repository::Subversion.generate!(:password => 'clear')
end
Redmine::Configuration.with 'database_cipher_key' => '' do
r = Repository.first(:order => 'id DESC')
# password can not be deciphered
assert_nothing_raised do
assert r.password.match(/\Aaes-256-cbc:.+\Z/)
end
end
end
def test_encrypt_all def test_encrypt_all
Repository.delete_all Repository.delete_all
Redmine::Configuration.with 'database_cipher_key' => nil do Redmine::Configuration.with 'database_cipher_key' => nil do
+1
View File
@@ -888,6 +888,7 @@ class ProjectTest < ActiveSupport::TestCase
assert query assert query
assert_equal @project, query.project assert_equal @project, query.project
end end
assert_equal @source_project.queries.map(&:user_id).sort, @project.queries.map(&:user_id).sort
end end
should "copy versions" do should "copy versions" do
@@ -71,7 +71,6 @@ module Redmine
custom_field_values.each do |custom_value| custom_field_values.each do |custom_value|
custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s) custom_value.value = values[custom_value.custom_field_id.to_s] if values.has_key?(custom_value.custom_field_id.to_s)
end if values.is_a?(Hash) end if values.is_a?(Hash)
self.custom_values = custom_field_values
end end
def custom_field_values def custom_field_values
@@ -92,6 +91,7 @@ module Redmine
end end
def save_custom_field_values def save_custom_field_values
self.custom_values = custom_field_values
custom_field_values.each(&:save) custom_field_values.each(&:save)
@custom_field_values_changed = false @custom_field_values_changed = false
@custom_field_values = nil @custom_field_values = nil
@@ -162,9 +162,10 @@ module CollectiveIdea #:nodoc:
end end
# Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree.
def rebuild! def rebuild!(force=false)
# Don't rebuild a valid tree. # Don't rebuild a valid tree.
return true if valid? # valid? doesn't strictly validate the tree
return true if !force && valid?
scope = lambda{|node|} scope = lambda{|node|}
if acts_as_nested_set_options[:scope] if acts_as_nested_set_options[:scope]
@@ -444,7 +445,7 @@ module CollectiveIdea #:nodoc:
# Prunes a branch off of the tree, shifting all of the elements on the right # Prunes a branch off of the tree, shifting all of the elements on the right
# back to the left so the counts still work. # back to the left so the counts still work.
def prune_from_tree def prune_from_tree
return if right.nil? || left.nil? || leaf? || !self.class.exists?(id) return if right.nil? || left.nil? || !self.class.exists?(id)
self.class.base_class.transaction do self.class.base_class.transaction do
reload_nested_set reload_nested_set