Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c2a6e1eeb7 | ||
|
|
2f9c2e6bd3 | ||
|
|
2df7c0ff3a | ||
|
|
f5d5077d2b | ||
|
|
94a1eb21a4 | ||
|
|
1f80a4b0d9 | ||
|
|
55220950d2 | ||
|
|
daea57a37c | ||
|
|
fe61739108 | ||
|
|
a4cd96e8b0 | ||
|
|
804302ce61 | ||
|
|
89ecbe9cdc | ||
|
|
aac3e1e51c | ||
|
|
595fef0d68 | ||
|
|
65a6e3985e | ||
|
|
f27a0eca5b | ||
|
|
2d34ab9235 | ||
|
|
03bff3308f | ||
|
|
006a1b4fd7 | ||
|
|
9095874a07 | ||
|
|
8ecfd1dcf8 | ||
|
|
35584bc53a | ||
|
|
21a16e0958 | ||
|
|
76d24e44bf | ||
|
|
efbdef9357 | ||
|
|
5eab4af70d | ||
|
|
96b2e00015 | ||
|
|
9939fbeef6 | ||
|
|
b369f82d15 | ||
|
|
0ad5dfaba0 | ||
|
|
d7d18689b7 |
@@ -238,7 +238,7 @@ class AccountController < ApplicationController
|
||||
def onthefly_creation_failed(user, auth_source_options = { })
|
||||
@user = user
|
||||
session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
|
||||
render register_path
|
||||
render :action => 'register'
|
||||
end
|
||||
|
||||
def invalid_credentials
|
||||
|
||||
@@ -398,7 +398,7 @@ private
|
||||
end
|
||||
|
||||
@issue.project = @project
|
||||
@issue.author = User.current
|
||||
@issue.author ||= User.current
|
||||
# Tracker must be set before custom field values
|
||||
@issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first)
|
||||
if @issue.tracker.nil?
|
||||
|
||||
@@ -1029,6 +1029,11 @@ module ApplicationHelper
|
||||
content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options))
|
||||
end
|
||||
|
||||
# Helper to render JSON in views
|
||||
def raw_json(arg)
|
||||
arg.to_json.to_s.gsub('/', '\/').html_safe
|
||||
end
|
||||
|
||||
def back_url
|
||||
url = params[:back_url]
|
||||
if url.nil? && referer = request.env['HTTP_REFERER']
|
||||
@@ -1095,8 +1100,14 @@ module ApplicationHelper
|
||||
unless @calendar_headers_tags_included
|
||||
@calendar_headers_tags_included = true
|
||||
content_for :header_tags do
|
||||
start_of_week = Setting.start_of_week
|
||||
start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank?
|
||||
# Redmine uses 1..7 (monday..sunday) in settings and locales
|
||||
# JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0
|
||||
start_of_week = start_of_week.to_i % 7
|
||||
|
||||
tags = javascript_tag(
|
||||
"var datepickerOptions={dateFormat: 'yy-mm-dd', " +
|
||||
"var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " +
|
||||
"showOn: 'button', buttonImageOnly: true, buttonImage: '" +
|
||||
path_to_image('/images/calendar.png') +
|
||||
"', showButtonPanel: true};")
|
||||
|
||||
@@ -84,17 +84,21 @@ class Issue < ActiveRecord::Base
|
||||
# Returns a SQL conditions string used to find all issues visible by the specified user
|
||||
def self.visible_condition(user, options={})
|
||||
Project.allowed_to_condition(user, :view_issues, options) do |role, user|
|
||||
case role.issues_visibility
|
||||
when 'all'
|
||||
nil
|
||||
when 'default'
|
||||
user_ids = [user.id] + user.groups.map(&:id)
|
||||
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||
when 'own'
|
||||
user_ids = [user.id] + user.groups.map(&:id)
|
||||
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||
if user.logged?
|
||||
case role.issues_visibility
|
||||
when 'all'
|
||||
nil
|
||||
when 'default'
|
||||
user_ids = [user.id] + user.groups.map(&:id)
|
||||
"(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||
when 'own'
|
||||
user_ids = [user.id] + user.groups.map(&:id)
|
||||
"(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))"
|
||||
else
|
||||
'1=0'
|
||||
end
|
||||
else
|
||||
'1=0'
|
||||
"(#{table_name}.is_private = #{connection.quoted_false})"
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -102,15 +106,19 @@ class Issue < ActiveRecord::Base
|
||||
# Returns true if usr or current user is allowed to view the issue
|
||||
def visible?(usr=nil)
|
||||
(usr || User.current).allowed_to?(:view_issues, self.project) do |role, user|
|
||||
case role.issues_visibility
|
||||
when 'all'
|
||||
true
|
||||
when 'default'
|
||||
!self.is_private? || self.author == user || user.is_or_belongs_to?(assigned_to)
|
||||
when 'own'
|
||||
self.author == user || user.is_or_belongs_to?(assigned_to)
|
||||
if user.logged?
|
||||
case role.issues_visibility
|
||||
when 'all'
|
||||
true
|
||||
when 'default'
|
||||
!self.is_private? || (self.author == user || user.is_or_belongs_to?(assigned_to))
|
||||
when 'own'
|
||||
self.author == user || user.is_or_belongs_to?(assigned_to)
|
||||
else
|
||||
false
|
||||
end
|
||||
else
|
||||
false
|
||||
!self.is_private?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -133,6 +133,11 @@ class Role < ActiveRecord::Base
|
||||
self.builtin != 0
|
||||
end
|
||||
|
||||
# Return true if the role is the anonymous role
|
||||
def anonymous?
|
||||
builtin == 2
|
||||
end
|
||||
|
||||
# Return true if the role is a project member role
|
||||
def member?
|
||||
!self.builtin?
|
||||
|
||||
@@ -44,7 +44,7 @@ class UserPreference < ActiveRecord::Base
|
||||
if attribute_present? attr_name
|
||||
super
|
||||
else
|
||||
h = read_attribute(:others).dup || {}
|
||||
h = (read_attribute(:others) || {}).dup
|
||||
h.update(attr_name => value)
|
||||
write_attribute(:others, h)
|
||||
value
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<%= l(:field_delay) %>: <%= f.text_field :delay, :size => 3 %> <%= l(:label_day_plural) %>
|
||||
</span>
|
||||
<%= submit_tag l(:button_add) %>
|
||||
<%= toggle_link l(:button_cancel), 'new-relation-form'%>
|
||||
<%= link_to_function l(:button_cancel), '$("#new-relation-form").hide();'%>
|
||||
</p>
|
||||
|
||||
<%= javascript_tag "observeAutocompleteField('relation_issue_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<%= javascript_tag do %>
|
||||
var operatorLabels = <%= raw Query.operators_labels.to_json %>;
|
||||
var operatorByType = <%= raw Query.operators_by_filter_type.to_json %>;
|
||||
var availableFilters = <%= raw query.available_filters_as_json.to_json %>;
|
||||
var labelDayPlural = "<%= raw escape_javascript(l(:label_day_plural)) %>";
|
||||
var operatorLabels = <%= raw_json Query.operators_labels %>;
|
||||
var operatorByType = <%= raw_json Query.operators_by_filter_type %>;
|
||||
var availableFilters = <%= raw_json query.available_filters_as_json %>;
|
||||
var labelDayPlural = <%= raw_json l(:label_day_plural) %>;
|
||||
$(document).ready(function(){
|
||||
initFilters();
|
||||
<% query.filters.each do |field, options| %>
|
||||
addFilter("<%= field %>", <%= raw query.operator_for(field).to_json %>, <%= raw query.values_for(field).to_json %>);
|
||||
addFilter("<%= field %>", <%= raw_json query.operator_for(field) %>, <%= raw_json query.values_for(field) %>);
|
||||
<% end %>
|
||||
});
|
||||
<% end %>
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<%= javascript_include_tag 'raphael.js' %>
|
||||
<%= javascript_include_tag 'revision_graph.js' %>
|
||||
<script type="text/javascript" charset="utf-8">
|
||||
<%= javascript_tag do %>
|
||||
function revisionGraphHandler(){
|
||||
drawRevisionGraph(
|
||||
document.getElementById('holder'),
|
||||
@@ -10,5 +8,11 @@ function revisionGraphHandler(){
|
||||
}
|
||||
$(document).ready(revisionGraphHandler);
|
||||
$(window).resize(revisionGraphHandler);
|
||||
</script>
|
||||
<% end %>
|
||||
|
||||
<div id="holder" class="revision-graph"></div>
|
||||
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'raphael' %>
|
||||
<%= javascript_include_tag 'revision_graph' %>
|
||||
<% end %>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<h2><%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %></h2>
|
||||
|
||||
<!-- Choose view type -->
|
||||
<%= form_tag({:path => to_path_param(@path)}, :method => 'get') do %>
|
||||
<%= hidden_field_tag('rev', params[:rev]) if params[:rev] %>
|
||||
<%= form_tag({:action => 'diff', :id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => to_path_param(@path), :rev=> @rev}, :method => 'get') do %>
|
||||
<%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>
|
||||
<p>
|
||||
<label><%= l(:label_view_diff) %></label>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<%= error_messages_for 'role' %>
|
||||
|
||||
<% unless @role.anonymous? %>
|
||||
<div class="box tabular">
|
||||
<% unless @role.builtin? %>
|
||||
<p><%= f.text_field :name, :required => true %></p>
|
||||
@@ -11,6 +12,7 @@
|
||||
<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name, params[:copy_workflow_from] || @copy_from.try(:id))) %></p>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<h3><%= l(:label_permissions) %></h3>
|
||||
<div class="box tabular" id="permissions">
|
||||
|
||||
@@ -80,9 +80,8 @@ bs:
|
||||
format:
|
||||
unit: 'KM'
|
||||
format: '%u %n'
|
||||
separator:
|
||||
delimiter:
|
||||
precision:
|
||||
negative_format: '%u -%n'
|
||||
delimiter: ''
|
||||
percentage:
|
||||
format:
|
||||
delimiter: ""
|
||||
|
||||
@@ -84,9 +84,7 @@ de:
|
||||
format:
|
||||
unit: '€'
|
||||
format: '%n %u'
|
||||
separator:
|
||||
delimiter:
|
||||
precision:
|
||||
delimiter: ''
|
||||
percentage:
|
||||
format:
|
||||
delimiter: ""
|
||||
|
||||
@@ -1087,9 +1087,9 @@ ja:
|
||||
label_readonly: 読み取り専用
|
||||
label_required: 必須
|
||||
text_repository_identifier_info: アルファベット小文字(a-z)・数字・ハイフン・アンダースコアが使えます。<br />識別子は後で変更することはできません。
|
||||
field_board_parent: Parent forum
|
||||
label_attribute_of_project: Project's %{name}
|
||||
label_attribute_of_author: Author's %{name}
|
||||
label_attribute_of_assigned_to: Assignee's %{name}
|
||||
label_attribute_of_fixed_version: Target version's %{name}
|
||||
label_copy_subtasks: Copy subtasks
|
||||
field_board_parent: 親フォーラム
|
||||
label_attribute_of_project: プロジェクトの %{name}
|
||||
label_attribute_of_author: 作成者の %{name}
|
||||
label_attribute_of_assigned_to: 担当者の %{name}
|
||||
label_attribute_of_fixed_version: 対象バージョンの %{name}
|
||||
label_copy_subtasks: 子チケットをコピー
|
||||
|
||||
@@ -939,6 +939,7 @@
|
||||
label_child_revision: 子項
|
||||
label_export_options: "%{export_format} 匯出選項"
|
||||
label_copy_attachments: 複製附件
|
||||
label_copy_subtasks: 複製子任務
|
||||
label_item_position: "%{position} / %{count}"
|
||||
label_completed_versions: 已完成版本
|
||||
label_search_for_watchers: 搜尋可供加入的監看者
|
||||
@@ -1143,4 +1144,3 @@
|
||||
description_date_from: 輸入起始日期
|
||||
description_date_to: 輸入結束日期
|
||||
text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。<br />一旦儲存之後, 代碼便無法再次被更改。'
|
||||
label_copy_subtasks: Copy subtasks
|
||||
|
||||
119
doc/CHANGELOG
119
doc/CHANGELOG
@@ -4,6 +4,125 @@ Redmine - project management software
|
||||
Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
http://www.redmine.org/
|
||||
|
||||
== 2012-09-30 v2.1.2
|
||||
|
||||
* Defect #11929: XSS vulnerability in Redmine 2.1.x
|
||||
|
||||
== 2012-09-30 v2.1.1
|
||||
|
||||
* Defect #11290: ParseDate missing in Ruby 1.9x
|
||||
* Defect #11844: "load_default_data" rake task fails to print the error message if one occurs
|
||||
* Defect #11850: Can't create a user from ldap by on-the-fly on the redmine server using URI prefix
|
||||
* Defect #11872: Private issue visible to anonymous users after its author is deleted
|
||||
* Defect #11885: Filter misses Selectionfield on IE8
|
||||
* Defect #11893: New relation form Cancel link is broken with Chrome 21
|
||||
* Defect #11905: Potential "can't dup NilClass" error in UserPreference
|
||||
* Defect #11909: Autocomplete results not reset after clearing search field
|
||||
* Defect #11922: bs.yml and de.yml lead to error by number_to_currency()
|
||||
* Defect #11945: rake task prints "can't convert Errno::EACCES into String" in case of no permission of public/plugin_assets
|
||||
* Defect #11975: Undefined status transitions allowed in workflow (author of issue changes when selecting a new status)
|
||||
* Defect #11982: SCM diff view generates extra parameter for switching mode
|
||||
* Patch #11897: Traditional Chinese language file (to r10433)
|
||||
|
||||
== 2012-09-16 v2.1.0
|
||||
|
||||
* Defect #2071: Reordering priority-enumerations breaks alternate-theme's issue-colouring
|
||||
* Defect #2190: Month names not translated to german
|
||||
* Defect #8978: LDAP timeout if an LDAP auth provider is unreachable
|
||||
* Defect #9839: Gantt abbr of weekday should not be necessarily the first letter of the long day name
|
||||
* Defect #10928: Documentation about generating a plugin is not up-to-date
|
||||
* Defect #11034: TLS configuration documentation for Rails 3
|
||||
* Defect #11073: UserCustomField order_statement returns wrong output
|
||||
* Defect #11153: Default sorting for target version is DESC instead of ASC
|
||||
* Defect #11207: Issues associated with a locked version are not copied when copying a project
|
||||
* Defect #11304: Issue-class: status-1, status-2 etc. refer to status position instead of status id
|
||||
* Defect #11331: Openid registration form should not require user to enter password
|
||||
* Defect #11345: Context menu should show shared versions when editing issues from different projects
|
||||
* Defect #11355: Plain text notification emails content is HTML escaped
|
||||
* Defect #11388: Updating a version through rest API returns invalid JSON
|
||||
* Defect #11389: Warning in awesome_nested_set.rb
|
||||
* Defect #11503: Accessing /projects/:project/wiki/something.png fails with error 500
|
||||
* Defect #11506: Versions that are not shared should not be assignable when selecting another project
|
||||
* Defect #11508: Projects not ordered alphabetically after renaming project
|
||||
* Defect #11540: Roadmap anchor links can be ambigous
|
||||
* Defect #11545: Overwriting existing method Issue.open
|
||||
* Defect #11552: MailHandler does not match assignee name with spaces
|
||||
* Defect #11571: Custom fields of type version not proper handled in receiving e-mails
|
||||
* Defect #11577: Can't use non-latin anchor in wiki
|
||||
* Defect #11612: Revision graph sometimes broken due to raphael.js error
|
||||
* Defect #11621: Redmine MIME Detection Of Javascript Files Non-Standard
|
||||
* Defect #11633: Macro arguments should not be parsed by text formatters
|
||||
* Defect #11662: Invalid query returned from Issues.visible scope after accessing User#projects_by_role with a role that is not present
|
||||
* Defect #11691: 404 response when deleting a user from the edit page
|
||||
* Defect #11723: redmine:send_reminders notification misses if assignee is a group
|
||||
* Defect #11738: Batch update of issues clears project path
|
||||
* Defect #11749: Redmine.pm: HEAD is not considered as a read-only method
|
||||
* Defect #11814: Date picker does not respect week start setting
|
||||
* Feature #703: Configurable required fields per tracker/status/role
|
||||
* Feature #1006: Display thumbnails of attached images
|
||||
* Feature #1091: Disabling default ticket fields per tracker
|
||||
* Feature #1360: Permission for adding an issue to a version.
|
||||
* Feature #3061: Let macros optionally match over multiple lines and ignore single curly braces
|
||||
* Feature #3510: Inserting image thumbnails inside the wiki
|
||||
* Feature #3521: Permissions for roles to change fields per tracker/status
|
||||
* Feature #3640: Freeze / Close Projects
|
||||
* Feature #3831: Support for subforums
|
||||
* Feature #6597: Configurable session lifetime and timeout
|
||||
* Feature #6965: Option to Copy Subtasks when copying an issue
|
||||
* Feature #8161: Ability to filter issues on project custom fields
|
||||
* Feature #8577: "Private" column and filter on the issue list
|
||||
* Feature #8981: REST Api for Groups
|
||||
* Feature #9258: Create role by copy
|
||||
* Feature #9419: Group/sort the issue list by user/version-format custom fields
|
||||
* Feature #10362: Show images in repositories inline when clicking the 'View' link
|
||||
* Feature #10419: Upgrade raphael.js (2.1.0)
|
||||
* Feature #11068: Ability to set default column order in issue list
|
||||
* Feature #11102: Add autocomplete to "Related issue" field on revision
|
||||
* Feature #11109: Repository Identifier should be frozen
|
||||
* Feature #11181: Additional "Log time" link on project overview
|
||||
* Feature #11205: Reversed order of priorities on the issue summary page
|
||||
* Feature #11445: Switch from Prototype to JQuery
|
||||
* Feature #11469: JSONP support
|
||||
* Feature #11475: Redmine.pm: Allow fallback to other Apache auth providers
|
||||
* Feature #11494: Don't turn #nnn with leading zeros into links
|
||||
* Feature #11539: Display a projects tree instead of a flat list in notification preferences
|
||||
* Feature #11578: Option to pass whole arguments to a macro without splitting them
|
||||
* Feature #11595: Missing mime type for svg files
|
||||
* Feature #11758: Upgrade to Rails 3.2.8
|
||||
* Patch #4905: Redmine.pm: add support for Git's smart HTTP protocol
|
||||
* Patch #10988: New Korean translation patch
|
||||
* Patch #11201: Korean translation special update
|
||||
* Patch #11401: Fix Japanese mistranslation for "button_submit"
|
||||
* Patch #11402: Japanese translation added for default role names
|
||||
* Patch #11411: Fix disordered use of long sound in Japanese "user" translation
|
||||
* Patch #11412: Unnatural Japanese message when users failed to login
|
||||
* Patch #11419: Fix wrong Japanese "label_attachment" translation
|
||||
* Patch #11496: Make labels clickable in Adminstration/Settings
|
||||
* Patch #11704: Avoid the use of tag("...", "...", true) in layout
|
||||
* Patch #11818: Redmine.pm fails when permissions are NULL
|
||||
|
||||
== 2012-09-16 v2.0.4
|
||||
|
||||
* Defect #10818: Running rake in test environment causes exception
|
||||
* Defect #11209: Wiki diff may generate broken HTML
|
||||
* Defect #11217: Project names in drop-down are escaped twice
|
||||
* Defect #11262: Link is escaped in wiki added/updated notification email
|
||||
* Defect #11307: Can't filter for negative numeric custom fields
|
||||
* Defect #11325: Unified diff link broken on specific file/revision diff view
|
||||
* Defect #11341: Escaped link in conflict resolution form
|
||||
* Defect #11365: Attachment description length is not validated
|
||||
* Defect #11511: Confirmation page has broken HTML when a project folding sub project is deleted
|
||||
* Defect #11533: rake redmine:plugins:test doesn't run tests in subdirectories
|
||||
* Defect #11541: Version sharing is missing in the REST API
|
||||
* Defect #11550: Issue reminder doesn't work when using asynchronous delivery
|
||||
* Defect #11776: Can't override mailer views inside redmine plugin.
|
||||
* Defect #11789: Edit section links broken with h5/h6 headings
|
||||
* Feature #11338: Exclude emails with auto-submitted => auto-generated
|
||||
* Patch #11299: redmine:plugins:migrate should update db/schema.rb
|
||||
* Patch #11328: Fix Japanese mistranslation for 'label_language_based'
|
||||
* Patch #11448: Russian translation for 1.4-stable and 2.0-stable
|
||||
* Patch #11600: Fix plural form of the abbreviation for hours in Brazilian Portuguese
|
||||
|
||||
== 2012-06-18 v2.0.3
|
||||
|
||||
* Defect #10688: PDF export from Wiki - Problems with tables
|
||||
|
||||
@@ -13,7 +13,7 @@ http://www.redmine.org/
|
||||
|
||||
* A database:
|
||||
* MySQL (tested with MySQL 5.1)
|
||||
* PostgreSQL (tested with PostgreSQL 8.4)
|
||||
* PostgreSQL (tested with PostgreSQL 9.1)
|
||||
* SQLite3 (tested with SQLite 3.6)
|
||||
|
||||
Optional:
|
||||
@@ -38,7 +38,10 @@ Optional:
|
||||
3. Create an empty utf8 encoded database: "redmine" for example
|
||||
|
||||
4. Configure the database parameters in config/database.yml
|
||||
for the "production" environment (default database is MySQL)
|
||||
for the "production" environment (default database is MySQL and ruby1.8)
|
||||
|
||||
If you're running Redmine with MySQL and ruby1.9, replace the adapter name
|
||||
with `mysql2`
|
||||
|
||||
5. Generate a session store secret
|
||||
|
||||
|
||||
@@ -249,7 +249,8 @@ sub RedmineDSN {
|
||||
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'))
|
||||
) ";
|
||||
)
|
||||
AND roles.permissions IS NOT NULL";
|
||||
$self->{RedmineQuery} = trim($query);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
require 'SVG/Graph/Plot'
|
||||
require 'parsedate'
|
||||
|
||||
module SVG
|
||||
module Graph
|
||||
@@ -157,8 +156,7 @@ module SVG
|
||||
y = []
|
||||
data[:data].each_index {|i|
|
||||
if i%2 == 0
|
||||
arr = ParseDate.parsedate( data[:data][i] )
|
||||
t = Time.local( *arr[0,6].compact )
|
||||
t = DateTime.parse( data[:data][i] ).to_time
|
||||
x << t.to_i
|
||||
else
|
||||
y << data[:data][i]
|
||||
@@ -173,8 +171,7 @@ module SVG
|
||||
protected
|
||||
|
||||
def min_x_value=(value)
|
||||
arr = ParseDate.parsedate( value )
|
||||
@min_x_value = Time.local( *arr[0,6].compact ).to_i
|
||||
@min_x_value = DateTime.parse( data[:data][i] ).to_time
|
||||
end
|
||||
|
||||
|
||||
|
||||
@@ -336,7 +336,11 @@ module Redmine #:nodoc:
|
||||
|
||||
unless source_files.empty?
|
||||
base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, ''))
|
||||
FileUtils.mkdir_p(base_target_dir)
|
||||
begin
|
||||
FileUtils.mkdir_p(base_target_dir)
|
||||
rescue Exception => e
|
||||
raise "Could not create directory #{base_target_dir}: " + e.message
|
||||
end
|
||||
end
|
||||
|
||||
source_dirs.each do |dir|
|
||||
@@ -346,7 +350,7 @@ module Redmine #:nodoc:
|
||||
begin
|
||||
FileUtils.mkdir_p(target_dir)
|
||||
rescue Exception => e
|
||||
raise "Could not create directory #{target_dir}: \n" + e
|
||||
raise "Could not create directory #{target_dir}: " + e.message
|
||||
end
|
||||
end
|
||||
|
||||
@@ -357,7 +361,7 @@ module Redmine #:nodoc:
|
||||
FileUtils.cp(file, target)
|
||||
end
|
||||
rescue Exception => e
|
||||
raise "Could not copy #{file} to #{target}: \n" + e
|
||||
raise "Could not copy #{file} to #{target}: " + e.message
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,13 +4,13 @@ module Redmine
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 1
|
||||
TINY = 0
|
||||
TINY = 2
|
||||
|
||||
# Branch values:
|
||||
# * official release: nil
|
||||
# * stable branch: stable
|
||||
# * trunk: devel
|
||||
BRANCH = 'devel'
|
||||
BRANCH = 'stable'
|
||||
|
||||
def self.revision
|
||||
revision = nil
|
||||
|
||||
@@ -26,9 +26,9 @@ namespace :redmine do
|
||||
Redmine::DefaultData::Loader.load(current_language)
|
||||
puts "Default configuration data loaded."
|
||||
rescue Redmine::DefaultData::DataAlreadyLoaded => error
|
||||
puts error
|
||||
puts error.message
|
||||
rescue => error
|
||||
puts "Error: " + error
|
||||
puts "Error: " + error.message
|
||||
puts "Default configuration data was not loaded."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -152,10 +152,10 @@ function buildFilterRow(field, operator, values) {
|
||||
var option = $('<option>');
|
||||
if ($.isArray(filterValue)) {
|
||||
option.val(filterValue[1]).text(filterValue[0]);
|
||||
if (values.indexOf(filterValue[1]) > -1) {option.attr('selected', true)};
|
||||
if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);}
|
||||
} else {
|
||||
option.val(filterValue).text(filterValue);
|
||||
if (values.indexOf(filterValue) > -1) {option.attr('selected', true)};
|
||||
if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);}
|
||||
}
|
||||
select.append(option);
|
||||
}
|
||||
@@ -163,9 +163,9 @@ function buildFilterRow(field, operator, values) {
|
||||
case "date":
|
||||
case "date_past":
|
||||
tr.find('td.values').append(
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" value="'+values[0]+'" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" value="'+values[1]+'" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" value="'+values[0]+'" /> '+labelDayPlural+'</span>'
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="10" class="value date_value" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="10" class="value date_value" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="3" class="value" /> '+labelDayPlural+'</span>'
|
||||
);
|
||||
$('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions);
|
||||
$('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions);
|
||||
@@ -174,15 +174,15 @@ function buildFilterRow(field, operator, values) {
|
||||
case "string":
|
||||
case "text":
|
||||
tr.find('td.values').append(
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" value="'+values[0]+'" /></span>'
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'" size="30" class="value" /></span>'
|
||||
);
|
||||
$('#values_'+fieldId).val(values[0]);
|
||||
break;
|
||||
case "integer":
|
||||
case "float":
|
||||
tr.find('td.values').append(
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" value="'+values[0]+'" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" value="'+values[1]+'" /></span>'
|
||||
'<span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_1" size="6" class="value" /></span>' +
|
||||
' <span style="display:none;"><input type="text" name="v['+field+'][]" id="values_'+fieldId+'_2" size="6" class="value" /></span>'
|
||||
);
|
||||
$('#values_'+fieldId+'_1').val(values[0]);
|
||||
$('#values_'+fieldId+'_2').val(values[1]);
|
||||
@@ -204,7 +204,7 @@ function toggleFilter(field) {
|
||||
function enableValues(field, indexes) {
|
||||
var fieldId = field.replace('.', '_');
|
||||
$('#tr_'+fieldId+' td.values .value').each(function(index) {
|
||||
if (indexes.indexOf(index) >= 0) {
|
||||
if ($.inArray(index, indexes) >= 0) {
|
||||
$(this).removeAttr('disabled');
|
||||
$(this).parents('span').first().show();
|
||||
} else {
|
||||
@@ -478,16 +478,14 @@ function observeSearchfield(fieldId, targetId, url) {
|
||||
var val = $this.val();
|
||||
if ($this.attr('data-value-was') != val){
|
||||
$this.attr('data-value-was', val);
|
||||
if (val != '') {
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
data: {q: $this.val()},
|
||||
success: function(data){ $('#'+targetId).html(data); },
|
||||
beforeSend: function(){ $this.addClass('ajax-loading'); },
|
||||
complete: function(){ $this.removeClass('ajax-loading'); }
|
||||
});
|
||||
}
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: 'get',
|
||||
data: {q: $this.val()},
|
||||
success: function(data){ $('#'+targetId).html(data); },
|
||||
beforeSend: function(){ $this.addClass('ajax-loading'); },
|
||||
complete: function(){ $this.removeClass('ajax-loading'); }
|
||||
});
|
||||
}
|
||||
};
|
||||
var reset = function() {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -35,6 +35,9 @@ function drawRevisionGraph(holder, commits_hash, graph_space) {
|
||||
var path, title;
|
||||
var revision_dot_overlay;
|
||||
$.each(commits, function(index, commit) {
|
||||
if (!commit.hasOwnProperty("space"))
|
||||
commit.space = 0;
|
||||
|
||||
y = commit_table_rows.eq(max_rdmid - commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
||||
x = graph_x_offset + XSTEP / 2 + XSTEP * commit.space;
|
||||
revisionGraph.circle(x, y, 3)
|
||||
@@ -46,6 +49,9 @@ function drawRevisionGraph(holder, commits_hash, graph_space) {
|
||||
$.each(commit.parent_scmids, function(index, parent_scmid) {
|
||||
parent_commit = commits_by_scmid[parent_scmid];
|
||||
if (parent_commit) {
|
||||
if (!parent_commit.hasOwnProperty("space"))
|
||||
parent_commit.space = 0;
|
||||
|
||||
parent_y = commit_table_rows.eq(max_rdmid - parent_commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET;
|
||||
parent_x = graph_x_offset + XSTEP / 2 + XSTEP * parent_commit.space;
|
||||
if (parent_commit.space == commit.space) {
|
||||
|
||||
@@ -96,8 +96,13 @@ class AttachmentsControllerTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def test_save_diff_type
|
||||
@request.session[:user_id] = 1 # admin
|
||||
user1 = User.find(1)
|
||||
user1.pref[:diff_type] = nil
|
||||
user1.preference.save
|
||||
user = User.find(1)
|
||||
assert_nil user.pref[:diff_type]
|
||||
|
||||
@request.session[:user_id] = 1 # admin
|
||||
get :show, :id => 5
|
||||
assert_response :success
|
||||
assert_template 'diff'
|
||||
|
||||
@@ -2521,6 +2521,18 @@ class IssuesControllerTest < ActionController::TestCase
|
||||
assert_equal 'This is the test_new issue', issue.subject
|
||||
end
|
||||
|
||||
def test_update_edit_form_should_keep_issue_author
|
||||
@request.session[:user_id] = 3
|
||||
xhr :put, :new, :project_id => 1, :id => 1, :issue => {:subject => 'Changed'}
|
||||
assert_response :success
|
||||
assert_equal 'text/javascript', response.content_type
|
||||
|
||||
issue = assigns(:issue)
|
||||
assert_equal User.find(2), issue.author
|
||||
assert_equal 2, issue.author_id
|
||||
assert_not_equal User.current, issue.author
|
||||
end
|
||||
|
||||
def test_update_edit_form_should_propose_transitions_based_on_initial_status
|
||||
@request.session[:user_id] = 2
|
||||
WorkflowTransition.delete_all
|
||||
|
||||
@@ -273,4 +273,12 @@ class QueriesControllerTest < ActionController::TestCase
|
||||
assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook', :set_filter => 1, :query_id => nil
|
||||
assert_nil Query.find_by_id(1)
|
||||
end
|
||||
|
||||
def test_backslash_should_be_escaped_in_filters
|
||||
@request.session[:user_id] = 2
|
||||
get :new, :subject => 'foo/bar'
|
||||
assert_response :success
|
||||
assert_template 'new'
|
||||
assert_include 'addFilter("subject", "=", ["foo\/bar"]);', response.body
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,8 +53,6 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
if @char_1.respond_to?(:force_encoding)
|
||||
@char_1.force_encoding('UTF-8')
|
||||
end
|
||||
|
||||
Setting.default_language = 'en'
|
||||
end
|
||||
|
||||
def test_create_and_update
|
||||
@@ -263,6 +261,8 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def test_diff
|
||||
assert_equal true, @repository.is_default
|
||||
assert_nil @repository.identifier
|
||||
assert_equal 0, @repository.changesets.count
|
||||
@repository.fetch_changesets
|
||||
@project.reload
|
||||
@@ -320,10 +320,12 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
with_settings :diff_max_lines_displayed => 5 do
|
||||
# Truncated diff of changeset 2f9c0091
|
||||
with_cache do
|
||||
get :diff, :id => PRJ_ID, :type => 'inline',
|
||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||
assert_response :success
|
||||
assert @response.body.include?("... This diff was truncated")
|
||||
with_settings :default_language => 'en' do
|
||||
get :diff, :id => PRJ_ID, :type => 'inline',
|
||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||
assert_response :success
|
||||
assert @response.body.include?("... This diff was truncated")
|
||||
end
|
||||
with_settings :default_language => 'fr' do
|
||||
get :diff, :id => PRJ_ID, :type => 'inline',
|
||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||
@@ -351,9 +353,55 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
diff = assigns(:diff)
|
||||
assert_not_nil diff
|
||||
assert_tag :tag => 'h2', :content => /2f9c0091:61b685fb/
|
||||
assert_tag :tag => "form",
|
||||
:attributes => {
|
||||
:action => "/projects/subproject1/repository/revisions/" +
|
||||
"61b685fbe55ab05b5ac68402d5720c1a6ac973d1/diff"
|
||||
}
|
||||
assert_tag :tag => 'input',
|
||||
:attributes => {
|
||||
:id => "rev_to",
|
||||
:name => "rev_to",
|
||||
:type => "hidden",
|
||||
:value => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
def test_diff_path_in_subrepo
|
||||
repo = Repository::Git.create(
|
||||
:project => @project,
|
||||
:url => REPOSITORY_PATH,
|
||||
:identifier => 'test-diff-path',
|
||||
:path_encoding => 'ISO-8859-1'
|
||||
);
|
||||
assert repo
|
||||
assert_equal false, repo.is_default
|
||||
assert_equal 'test-diff-path', repo.identifier
|
||||
get :diff,
|
||||
:id => PRJ_ID,
|
||||
:repository_id => 'test-diff-path',
|
||||
:rev => '61b685fbe55ab05b',
|
||||
:rev_to => '2f9c0091c754a91a',
|
||||
:type => 'inline'
|
||||
assert_response :success
|
||||
assert_template 'diff'
|
||||
diff = assigns(:diff)
|
||||
assert_not_nil diff
|
||||
assert_tag :tag => "form",
|
||||
:attributes => {
|
||||
:action => "/projects/subproject1/repository/test-diff-path/" +
|
||||
"revisions/61b685fbe55ab05b/diff"
|
||||
}
|
||||
assert_tag :tag => 'input',
|
||||
:attributes => {
|
||||
:id => "rev_to",
|
||||
:name => "rev_to",
|
||||
:type => "hidden",
|
||||
:value => '2f9c0091c754a91a'
|
||||
}
|
||||
end
|
||||
|
||||
def test_diff_latin_1
|
||||
if @ruby19_non_utf8_pass
|
||||
puts_ruby19_non_utf8_pass()
|
||||
@@ -385,8 +433,13 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def test_save_diff_type
|
||||
@request.session[:user_id] = 1 # admin
|
||||
user1 = User.find(1)
|
||||
user1.pref[:diff_type] = nil
|
||||
user1.preference.save
|
||||
user = User.find(1)
|
||||
assert_nil user.pref[:diff_type]
|
||||
|
||||
@request.session[:user_id] = 1 # admin
|
||||
get :diff,
|
||||
:id => PRJ_ID,
|
||||
:rev => '2f9c0091c754a91af7a9c478e36556b4bde8dcf7'
|
||||
|
||||
@@ -110,6 +110,14 @@ class RolesControllerTest < ActionController::TestCase
|
||||
assert_response :success
|
||||
assert_template 'edit'
|
||||
assert_equal Role.find(1), assigns(:role)
|
||||
assert_select 'select[name=?]', 'role[issues_visibility]'
|
||||
end
|
||||
|
||||
def test_edit_anonymous
|
||||
get :edit, :id => Role.anonymous.id
|
||||
assert_response :success
|
||||
assert_template 'edit'
|
||||
assert_select 'select[name=?]', 'role[issues_visibility]', 0
|
||||
end
|
||||
|
||||
def test_edit_invalid_should_respond_with_404
|
||||
|
||||
@@ -22,6 +22,8 @@ require File.expand_path('../../test_helper', __FILE__)
|
||||
class BoardTest < ActiveSupport::TestCase
|
||||
fixtures :projects, :boards, :messages, :attachments, :watchers
|
||||
|
||||
include Redmine::I18n
|
||||
|
||||
def setup
|
||||
@project = Project.find(1)
|
||||
end
|
||||
@@ -41,6 +43,7 @@ class BoardTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
def test_parent_should_be_in_same_project
|
||||
set_language_if_valid 'en'
|
||||
board = Board.new(:project_id => 3, :name => 'Test', :description => 'Test', :parent_id => 1)
|
||||
assert !board.save
|
||||
assert_include "Parent forum is invalid", board.errors.full_messages
|
||||
|
||||
@@ -179,7 +179,8 @@ class ChangesetTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
def test_commit_closing_a_subproject_issue
|
||||
with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes' do
|
||||
with_settings :commit_fix_status_id => 5, :commit_fix_keywords => 'closes',
|
||||
:default_language => 'en' do
|
||||
issue = Issue.find(5)
|
||||
assert !issue.closed?
|
||||
assert_difference 'Journal.count' do
|
||||
|
||||
@@ -25,7 +25,7 @@ class IssueTest < ActiveSupport::TestCase
|
||||
:versions,
|
||||
:issue_statuses, :issue_categories, :issue_relations, :workflows,
|
||||
:enumerations,
|
||||
:issues,
|
||||
:issues, :journals, :journal_details,
|
||||
:custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values,
|
||||
:time_entries
|
||||
|
||||
@@ -105,18 +105,6 @@ class IssueTest < ActiveSupport::TestCase
|
||||
assert_visibility_match User.anonymous, issues
|
||||
end
|
||||
|
||||
def test_visible_scope_for_anonymous_with_own_issues_visibility
|
||||
Role.anonymous.update_attribute :issues_visibility, 'own'
|
||||
Issue.create!(:project_id => 1, :tracker_id => 1,
|
||||
:author_id => User.anonymous.id,
|
||||
:subject => 'Issue by anonymous')
|
||||
|
||||
issues = Issue.visible(User.anonymous).all
|
||||
assert issues.any?
|
||||
assert_nil issues.detect {|issue| issue.author != User.anonymous}
|
||||
assert_visibility_match User.anonymous, issues
|
||||
end
|
||||
|
||||
def test_visible_scope_for_anonymous_without_view_issues_permissions
|
||||
# Anonymous user should not see issues without permission
|
||||
Role.anonymous.remove_permission!(:view_issues)
|
||||
@@ -125,6 +113,20 @@ class IssueTest < ActiveSupport::TestCase
|
||||
assert_visibility_match User.anonymous, issues
|
||||
end
|
||||
|
||||
def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_default
|
||||
assert Role.anonymous.update_attribute(:issues_visibility, 'default')
|
||||
issue = Issue.generate_for_project!(Project.find(1), :author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
|
||||
assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
|
||||
assert !issue.visible?(User.anonymous)
|
||||
end
|
||||
|
||||
def test_anonymous_should_not_see_private_issues_with_issues_visibility_set_to_own
|
||||
assert Role.anonymous.update_attribute(:issues_visibility, 'own')
|
||||
issue = Issue.generate_for_project!(Project.find(1), :author => User.anonymous, :assigned_to => User.anonymous, :is_private => true)
|
||||
assert_nil Issue.where(:id => issue.id).visible(User.anonymous).first
|
||||
assert !issue.visible?(User.anonymous)
|
||||
end
|
||||
|
||||
def test_visible_scope_for_non_member
|
||||
user = User.find(9)
|
||||
assert user.projects.empty?
|
||||
|
||||
@@ -171,6 +171,24 @@ class Redmine::I18nTest < ActiveSupport::TestCase
|
||||
assert_equal 'j', day_letter(4)
|
||||
end
|
||||
|
||||
def test_number_to_currency_for_each_language
|
||||
valid_languages.each do |lang|
|
||||
set_language_if_valid lang
|
||||
assert_nothing_raised "#{lang} failure" do
|
||||
number_to_currency(-1000.2)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def test_number_to_currency_default
|
||||
set_language_if_valid 'bs'
|
||||
assert_equal "KM -1000,20", number_to_currency(-1000.2)
|
||||
set_language_if_valid 'de'
|
||||
euro_sign = "\xe2\x82\xac"
|
||||
euro_sign.force_encoding('UTF-8') if euro_sign.respond_to?(:force_encoding)
|
||||
assert_equal "-1000,20 #{euro_sign}", number_to_currency(-1000.2)
|
||||
end
|
||||
|
||||
def test_valid_languages
|
||||
assert valid_languages.is_a?(Array)
|
||||
assert valid_languages.first.is_a?(Symbol)
|
||||
|
||||
@@ -54,4 +54,19 @@ class UserPreferenceTest < ActiveSupport::TestCase
|
||||
assert up.save
|
||||
assert_kind_of Hash, up.others
|
||||
end
|
||||
|
||||
def test_reading_value_from_nil_others_hash
|
||||
up = UserPreference.new(:user => User.new)
|
||||
up.others = nil
|
||||
assert_nil up.others
|
||||
assert_nil up[:foo]
|
||||
end
|
||||
|
||||
def test_writing_value_to_nil_others_hash
|
||||
up = UserPreference.new(:user => User.new)
|
||||
up.others = nil
|
||||
assert_nil up.others
|
||||
up[:foo] = 'bar'
|
||||
assert_equal 'bar', up[:foo]
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user