Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
87e8b02828 | ||
|
|
342b3302cf | ||
|
|
32e3d6e1b1 | ||
|
|
8d2d46bd8e | ||
|
|
7f03576b8d | ||
|
|
e757600b39 | ||
|
|
68560c13fe | ||
|
|
309f7b75fd | ||
|
|
dbb93692ff | ||
|
|
5f6289d6be | ||
|
|
081ee54bee | ||
|
|
1d0fb85179 | ||
|
|
887e7f8647 | ||
|
|
df05edff3d | ||
|
|
67057ea3e9 | ||
|
|
381e7156c2 | ||
|
|
f9ee57f2c1 | ||
|
|
fc13aef5bb | ||
|
|
4973350243 | ||
|
|
fcbb8acdb7 | ||
|
|
d79258f17f | ||
|
|
c4736ed42b | ||
|
|
47fb2eb998 | ||
|
|
e9813791cb | ||
|
|
5f23ebc31c | ||
|
|
b88c95b0fb | ||
|
|
93d8f99884 | ||
|
|
07edb10518 |
2
Gemfile
2
Gemfile
@@ -1,6 +1,6 @@
|
||||
source 'http://rubygems.org'
|
||||
|
||||
gem 'rails', '3.2.3'
|
||||
gem 'rails', '3.2.6'
|
||||
gem 'prototype-rails', '3.2.1'
|
||||
gem "i18n", "~> 0.6.0"
|
||||
gem "coderay", "~> 1.0.6"
|
||||
|
||||
@@ -445,9 +445,9 @@ class ApplicationController < ActionController::Base
|
||||
# Returns the API key present in the request
|
||||
def api_key_from_request
|
||||
if params[:key].present?
|
||||
params[:key]
|
||||
params[:key].to_s
|
||||
elsif request.headers["X-Redmine-API-Key"].present?
|
||||
request.headers["X-Redmine-API-Key"]
|
||||
request.headers["X-Redmine-API-Key"].to_s
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -43,10 +43,10 @@ class BoardsController < ApplicationController
|
||||
|
||||
@topic_count = @board.topics.count
|
||||
@topic_pages = Paginator.new self, @topic_count, per_page_option, params['page']
|
||||
@topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '),
|
||||
@topics = @board.topics.reorder("#{Message.table_name}.sticky DESC").order(sort_clause).all(
|
||||
:include => [:author, {:last_reply => :author}],
|
||||
:limit => @topic_pages.items_per_page,
|
||||
:offset => @topic_pages.current.offset
|
||||
:offset => @topic_pages.current.offset)
|
||||
@message = Message.new(:board => @board)
|
||||
render :action => 'show', :layout => !request.xhr?
|
||||
}
|
||||
|
||||
@@ -18,12 +18,13 @@
|
||||
class TimelogController < ApplicationController
|
||||
menu_item :issues
|
||||
|
||||
before_filter :find_project, :only => [:create]
|
||||
before_filter :find_project_for_new_time_entry, :only => [:create]
|
||||
before_filter :find_time_entry, :only => [:show, :edit, :update]
|
||||
before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy]
|
||||
before_filter :authorize, :except => [:new, :index, :report]
|
||||
|
||||
before_filter :find_optional_project, :only => [:new, :index, :report]
|
||||
before_filter :find_optional_project, :only => [:index, :report]
|
||||
before_filter :find_optional_project_for_new_time_entry, :only => [:new]
|
||||
before_filter :authorize_global, :only => [:new, :index, :report]
|
||||
|
||||
accept_rss_auth :index
|
||||
@@ -38,7 +39,7 @@ class TimelogController < ApplicationController
|
||||
|
||||
def index
|
||||
sort_init 'spent_on', 'desc'
|
||||
sort_update 'spent_on' => 'spent_on',
|
||||
sort_update 'spent_on' => ['spent_on', "#{TimeEntry.table_name}.created_on"],
|
||||
'user' => 'user_id',
|
||||
'activity' => 'activity_id',
|
||||
'project' => "#{Project.table_name}.name",
|
||||
@@ -133,9 +134,13 @@ class TimelogController < ApplicationController
|
||||
flash[:notice] = l(:notice_successful_create)
|
||||
if params[:continue]
|
||||
if params[:project_id]
|
||||
redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue, :back_url => params[:back_url]
|
||||
redirect_to :action => 'new', :project_id => @time_entry.project, :issue_id => @time_entry.issue,
|
||||
:time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
|
||||
:back_url => params[:back_url]
|
||||
else
|
||||
redirect_to :action => 'new', :back_url => params[:back_url]
|
||||
redirect_to :action => 'new',
|
||||
:time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id},
|
||||
:back_url => params[:back_url]
|
||||
end
|
||||
else
|
||||
redirect_back_or_default :action => 'index', :project_id => @time_entry.project
|
||||
@@ -258,7 +263,7 @@ private
|
||||
end
|
||||
end
|
||||
|
||||
def find_project
|
||||
def find_optional_project_for_new_time_entry
|
||||
if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present?
|
||||
@project = Project.find(project_id)
|
||||
end
|
||||
@@ -266,14 +271,17 @@ private
|
||||
@issue = Issue.find(issue_id)
|
||||
@project ||= @issue.project
|
||||
end
|
||||
if @project.nil?
|
||||
render_404
|
||||
return false
|
||||
end
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
render_404
|
||||
end
|
||||
|
||||
def find_project_for_new_time_entry
|
||||
find_optional_project_for_new_time_entry
|
||||
if @project.nil?
|
||||
render_404
|
||||
end
|
||||
end
|
||||
|
||||
def find_optional_project
|
||||
if !params[:issue_id].blank?
|
||||
@issue = Issue.find(params[:issue_id])
|
||||
|
||||
@@ -46,17 +46,17 @@ module RepositoriesHelper
|
||||
end
|
||||
|
||||
def render_changeset_changes
|
||||
changes = @changeset.changes.find(:all, :limit => 1000, :order => 'path').collect do |change|
|
||||
changes = @changeset.filechanges.find(:all, :limit => 1000, :order => 'path').collect do |change|
|
||||
case change.action
|
||||
when 'A'
|
||||
# Detects moved/copied files
|
||||
if !change.from_path.blank?
|
||||
change.action =
|
||||
@changeset.changes.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
||||
@changeset.filechanges.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C'
|
||||
end
|
||||
change
|
||||
when 'D'
|
||||
@changeset.changes.detect {|c| c.from_path == change.path} ? nil : change
|
||||
@changeset.filechanges.detect {|c| c.from_path == change.path} ? nil : change
|
||||
else
|
||||
change
|
||||
end
|
||||
|
||||
@@ -20,7 +20,7 @@ require 'iconv'
|
||||
class Changeset < ActiveRecord::Base
|
||||
belongs_to :repository
|
||||
belongs_to :user
|
||||
has_many :changes, :dependent => :delete_all
|
||||
has_many :filechanges, :class_name => 'Change', :dependent => :delete_all
|
||||
has_and_belongs_to_many :issues
|
||||
has_and_belongs_to_many :parents,
|
||||
:class_name => "Changeset",
|
||||
|
||||
@@ -124,6 +124,28 @@ class Issue < ActiveRecord::Base
|
||||
end
|
||||
end
|
||||
|
||||
# AR#Persistence#destroy would raise and RecordNotFound exception
|
||||
# if the issue was already deleted or updated (non matching lock_version).
|
||||
# This is a problem when bulk deleting issues or deleting a project
|
||||
# (because an issue may already be deleted if its parent was deleted
|
||||
# first).
|
||||
# The issue is reloaded by the nested_set before being deleted so
|
||||
# the lock_version condition should not be an issue but we handle it.
|
||||
def destroy
|
||||
super
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
# Stale or already deleted
|
||||
begin
|
||||
reload
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
# The issue was actually already deleted
|
||||
@destroyed = true
|
||||
return freeze
|
||||
end
|
||||
# The issue was stale, retry to destroy
|
||||
super
|
||||
end
|
||||
|
||||
# Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields
|
||||
def available_custom_fields
|
||||
(project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : []
|
||||
|
||||
@@ -163,7 +163,7 @@ class MailHandler < ActionMailer::Base
|
||||
issue = Issue.new(:author => user, :project => project)
|
||||
issue.safe_attributes = issue_attributes_from_keywords(issue)
|
||||
issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)}
|
||||
issue.subject = email.subject.to_s.chomp[0,255]
|
||||
issue.subject = cleaned_up_subject
|
||||
if issue.subject.blank?
|
||||
issue.subject = '(no subject)'
|
||||
end
|
||||
@@ -223,7 +223,7 @@ class MailHandler < ActionMailer::Base
|
||||
end
|
||||
|
||||
if !message.locked?
|
||||
reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip,
|
||||
reply = Message.new(:subject => cleaned_up_subject.gsub(%r{^.*msg\d+\]}, '').strip,
|
||||
:content => cleaned_up_text_body)
|
||||
reply.author = user
|
||||
reply.board = message.board
|
||||
@@ -364,6 +364,23 @@ class MailHandler < ActionMailer::Base
|
||||
cleanup_body(plain_text_body)
|
||||
end
|
||||
|
||||
def cleaned_up_subject
|
||||
subject = email.subject.to_s
|
||||
unless subject.respond_to?(:encoding)
|
||||
# try to reencode to utf8 manually with ruby1.8
|
||||
begin
|
||||
if h = email.header[:subject]
|
||||
if m = h.value.match(/^=\?([^\?]+)\?/)
|
||||
subject = Redmine::CodesetUtil.to_utf8(subject, m[1])
|
||||
end
|
||||
end
|
||||
rescue
|
||||
# nop
|
||||
end
|
||||
end
|
||||
subject.strip[0,255]
|
||||
end
|
||||
|
||||
def self.full_sanitizer
|
||||
@full_sanitizer ||= HTML::FullSanitizer.new
|
||||
end
|
||||
|
||||
@@ -22,7 +22,7 @@ class Repository < ActiveRecord::Base
|
||||
|
||||
belongs_to :project
|
||||
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
|
||||
has_many :changes, :through => :changesets
|
||||
has_many :filechanges, :class_name => 'Change', :through => :changesets
|
||||
|
||||
serialize :extra_info
|
||||
|
||||
@@ -228,7 +228,7 @@ class Repository < ActiveRecord::Base
|
||||
:order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC",
|
||||
:limit => limit)
|
||||
else
|
||||
changes.find(
|
||||
filechanges.find(
|
||||
:all,
|
||||
:include => {:changeset => :user},
|
||||
:conditions => ["path = ?", path.with_leading_slash],
|
||||
|
||||
@@ -54,7 +54,7 @@ class Repository::Cvs < Repository
|
||||
if entries
|
||||
entries.each() do |entry|
|
||||
if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? )
|
||||
change=changes.find_by_revision_and_path(
|
||||
change = filechanges.find_by_revision_and_path(
|
||||
entry.lastrev.revision,
|
||||
scm.with_leading_slash(entry.path) )
|
||||
if change
|
||||
@@ -94,7 +94,7 @@ class Repository::Cvs < Repository
|
||||
if rev_to.to_i > 0
|
||||
changeset_to = changesets.find_by_revision(rev_to)
|
||||
end
|
||||
changeset_from.changes.each() do |change_from|
|
||||
changeset_from.filechanges.each() do |change_from|
|
||||
revision_from = nil
|
||||
revision_to = nil
|
||||
if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path))
|
||||
@@ -102,7 +102,7 @@ class Repository::Cvs < Repository
|
||||
end
|
||||
if revision_from
|
||||
if changeset_to
|
||||
changeset_to.changes.each() do |change_to|
|
||||
changeset_to.filechanges.each() do |change_to|
|
||||
revision_to = change_to.revision if change_to.path == change_from.path
|
||||
end
|
||||
end
|
||||
@@ -133,7 +133,7 @@ class Repository::Cvs < Repository
|
||||
# only add the change to the database, if it doen't exists. the cvs log
|
||||
# is not exclusive at all.
|
||||
tmp_time = revision.time.clone
|
||||
unless changes.find_by_path_and_revision(
|
||||
unless filechanges.find_by_path_and_revision(
|
||||
scm.with_leading_slash(revision.paths[0][:path]),
|
||||
revision.paths[0][:revision]
|
||||
)
|
||||
|
||||
@@ -79,7 +79,7 @@ class Repository::Darcs < Repository
|
||||
return nil if patch_from.nil?
|
||||
patch_to = changesets.find_by_revision(rev_to) if rev_to
|
||||
if path.blank?
|
||||
path = patch_from.changes.collect{|change| change.path}.join(' ')
|
||||
path = patch_from.filechanges.collect{|change| change.path}.join(' ')
|
||||
end
|
||||
patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil
|
||||
end
|
||||
|
||||
@@ -66,7 +66,7 @@ class TimeEntry < ActiveRecord::Base
|
||||
end
|
||||
}
|
||||
|
||||
safe_attributes 'hours', 'comments', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values'
|
||||
safe_attributes 'hours', 'comments', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields'
|
||||
|
||||
def initialize(attributes=nil, *args)
|
||||
super
|
||||
|
||||
@@ -130,8 +130,11 @@ class User < Principal
|
||||
|
||||
# Returns the user that matches provided login and password, or nil
|
||||
def self.try_to_login(login, password)
|
||||
login = login.to_s
|
||||
password = password.to_s
|
||||
|
||||
# Make sure no one can sign in with an empty password
|
||||
return nil if password.to_s.empty?
|
||||
return nil if password.empty?
|
||||
user = find_by_login(login)
|
||||
if user
|
||||
# user is already in local database
|
||||
@@ -164,7 +167,7 @@ class User < Principal
|
||||
|
||||
# Returns the user who matches the given autologin +key+ or nil
|
||||
def self.try_to_autologin(key)
|
||||
tokens = Token.find_all_by_action_and_value('autologin', key)
|
||||
tokens = Token.find_all_by_action_and_value('autologin', key.to_s)
|
||||
# Make sure there's only 1 token that matches the key
|
||||
if tokens.size == 1
|
||||
token = tokens.first
|
||||
@@ -338,12 +341,12 @@ class User < Principal
|
||||
end
|
||||
|
||||
def self.find_by_rss_key(key)
|
||||
token = Token.find_by_value(key)
|
||||
token = Token.find_by_action_and_value('feeds', key.to_s)
|
||||
token && token.user.active? ? token.user : nil
|
||||
end
|
||||
|
||||
def self.find_by_api_key(key)
|
||||
token = Token.find_by_action_and_value('api', key)
|
||||
token = Token.find_by_action_and_value('api', key.to_s)
|
||||
token && token.user.active? ? token.user : nil
|
||||
end
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)) %></h2>
|
||||
<h2><%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %></h2>
|
||||
<p class="subtitle"><%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %></p>
|
||||
|
||||
<div id="activity">
|
||||
|
||||
@@ -7,14 +7,14 @@
|
||||
<div class="next-prev-links contextual">
|
||||
<%= link_to_if @prev_issue_id,
|
||||
"\xc2\xab #{l(:label_previous)}",
|
||||
issue_path(@prev_issue_id),
|
||||
(@prev_issue_id ? issue_path(@prev_issue_id) : nil),
|
||||
:title => "##{@prev_issue_id}" %> |
|
||||
<% if @issue_position && @issue_count %>
|
||||
<span class="position"><%= l(:label_item_position, :position => @issue_position, :count => @issue_count) %></span> |
|
||||
<% end %>
|
||||
<%= link_to_if @next_issue_id,
|
||||
"#{l(:label_next)} \xc2\xbb",
|
||||
issue_path(@next_issue_id),
|
||||
(@next_issue_id ? issue_path(@next_issue_id) : nil),
|
||||
:title => "##{@next_issue_id}" %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<%= labelled_remote_form_for @wiki,
|
||||
:as => :wiki,
|
||||
:url => { :controller => 'wikis', :action => 'edit', :id => @project } do |f| %>
|
||||
:url => { :controller => 'wikis', :action => 'edit', :id => @project }, :method => 'post' do |f| %>
|
||||
|
||||
<%= error_messages_for 'wiki' %>
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<h2><%= l(:label_repository) %></h2>
|
||||
|
||||
<%= labelled_form_for :repository, @repository, :url => repository_path(@path), :html => {:method => :put} do |f| %>
|
||||
<%= labelled_form_for :repository, @repository, :url => repository_path(@repository), :html => {:method => :put} do |f| %>
|
||||
<%= render :partial => 'form', :locals => {:f => f} %>
|
||||
<% end %>
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
:id => @project,
|
||||
:repository_id => @repository.identifier_param,
|
||||
:path => "",
|
||||
:rev => @changeset.identifier) if @changeset.changes.any? %></p>
|
||||
:rev => @changeset.identifier) if @changeset.filechanges.any? %></p>
|
||||
|
||||
<div class="changeset-changes">
|
||||
<%= render_changeset_changes %>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<h2><%= l(:label_spent_time) %></h2>
|
||||
|
||||
<%= labelled_form_for @time_entry, :url => time_entries_path do |f| %>
|
||||
<%= hidden_field_tag 'project_id', params[:project_id] if params[:project_id] %>
|
||||
<%= render :partial => 'form', :locals => {:f => f} %>
|
||||
<%= submit_tag l(:button_create) %>
|
||||
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<%= select_tag 'user[mail_notification]', options_for_select(user_mail_notification_options(@user), @user.mail_notification),
|
||||
:onchange => 'if (this.value == "selected") {Element.show("notified-projects")} else {Element.hide("notified-projects")}' %>
|
||||
</p>
|
||||
<% content_tag 'div', :id => 'notified-projects', :style => (@user.mail_notification == 'selected' ? '' : 'display:none;') do %>
|
||||
<%= content_tag 'div', :id => 'notified-projects', :style => (@user.mail_notification == 'selected' ? '' : 'display:none;') do %>
|
||||
<p><% @user.projects.each do |project| %>
|
||||
<label><%= check_box_tag 'notified_project_ids[]', project.id, @user.notified_projects_ids.include?(project.id) %> <%=h project.name %></label><br />
|
||||
<% end %></p>
|
||||
|
||||
@@ -76,14 +76,14 @@ ar:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -78,7 +78,7 @@ bg:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -89,7 +89,7 @@ bs:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -80,7 +80,7 @@ ca:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -81,14 +81,14 @@ cs:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Bajt"
|
||||
other: "Bajtů"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -91,7 +91,7 @@ da:
|
||||
format:
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -93,7 +93,7 @@ de:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
@@ -1036,7 +1036,7 @@ de:
|
||||
label_copy_attachments: Anhänge Kopieren
|
||||
label_item_position: "%{position}/%{count}"
|
||||
label_completed_versions: Abgeschlossene Versionen
|
||||
field_multiple: Mehrer Werte
|
||||
field_multiple: Mehrere Werte
|
||||
setting_commit_cross_project_ref: Erlauben auf Tickets aller anderen Projekte zu referenzieren
|
||||
text_issue_conflict_resolution_add_notes: Meine Änderungen übernehmen und alle anderen Änderungen verwerfen
|
||||
text_issue_conflict_resolution_overwrite: Meine Änderungen trotzdem übernehmen (vorherige Notizen bleiben erhalten aber manche können überschrieben werden)
|
||||
|
||||
@@ -77,7 +77,7 @@ el:
|
||||
precision: 3
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -81,14 +81,14 @@ en-GB:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -77,14 +77,14 @@ en:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -48,7 +48,7 @@ es:
|
||||
# These three are to override number.format and are optional
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -94,7 +94,7 @@ et:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -79,7 +79,7 @@ eu:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -77,7 +77,7 @@ fa:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -64,7 +64,7 @@ fi:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -91,7 +91,7 @@ fr:
|
||||
format: '%n %u'
|
||||
human:
|
||||
format:
|
||||
precision: 2
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -32,7 +32,7 @@ gl:
|
||||
format:
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -72,7 +72,7 @@ hr:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -97,7 +97,7 @@
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -78,7 +78,7 @@ id:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -96,7 +96,7 @@ ja:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -119,7 +119,7 @@ ko:
|
||||
# These three are to override number.format and are optional
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -109,7 +109,7 @@ lt:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
# Storage units output formatting.
|
||||
# %u is the storage unit, %n is the number (default: 2 MB)
|
||||
|
||||
@@ -72,7 +72,7 @@ lv:
|
||||
human:
|
||||
format:
|
||||
delimiter: " "
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -77,7 +77,7 @@ mk:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -75,7 +75,7 @@ mn:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -74,7 +74,7 @@ nl:
|
||||
precision: 3
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -63,7 +63,7 @@
|
||||
other: "nesten %{count} år"
|
||||
number:
|
||||
format:
|
||||
precision: 2
|
||||
precision: 3
|
||||
separator: "."
|
||||
delimiter: ","
|
||||
currency:
|
||||
|
||||
@@ -21,7 +21,7 @@ pl:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -97,7 +97,7 @@ pt-BR:
|
||||
delimiter: '.'
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: '.'
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -89,7 +89,7 @@ pt:
|
||||
delimiter: ''
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ''
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -73,7 +73,7 @@ ro:
|
||||
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -68,7 +68,7 @@ ru:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 2
|
||||
precision: 3
|
||||
# Rails 2.2
|
||||
# storage_units: [байт, КБ, МБ, ГБ, ТБ]
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ sk:
|
||||
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -75,7 +75,7 @@ sl:
|
||||
precision: 3
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -77,14 +77,14 @@ sq:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -77,7 +77,7 @@ sr-YU:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -77,7 +77,7 @@ sr:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -47,14 +47,14 @@ sv:
|
||||
# These three are to override number.format and are optional
|
||||
# separator:
|
||||
delimiter: ""
|
||||
# precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -74,7 +74,7 @@ th:
|
||||
precision: 3
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -99,7 +99,7 @@ tr:
|
||||
format:
|
||||
delimiter: '.'
|
||||
separator: ','
|
||||
precision: 2
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -74,7 +74,7 @@ uk:
|
||||
precision: 3
|
||||
human:
|
||||
format:
|
||||
precision: 1
|
||||
precision: 3
|
||||
delimiter: ""
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
|
||||
@@ -48,7 +48,7 @@ vi:
|
||||
# These three are to override number.format and are optional
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
# 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值
|
||||
# separator:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
# 儲存單位輸出格式.
|
||||
# %u 是儲存單位, %n 是數值 (預設值: 2 MB)
|
||||
storage_units:
|
||||
|
||||
@@ -79,14 +79,14 @@ zh:
|
||||
human:
|
||||
format:
|
||||
delimiter: ""
|
||||
precision: 1
|
||||
precision: 3
|
||||
storage_units:
|
||||
format: "%n %u"
|
||||
units:
|
||||
byte:
|
||||
one: "Byte"
|
||||
other: "Bytes"
|
||||
kb: "kB"
|
||||
kb: "KB"
|
||||
mb: "MB"
|
||||
gb: "GB"
|
||||
tb: "TB"
|
||||
|
||||
@@ -4,6 +4,33 @@ Redmine - project management software
|
||||
Copyright (C) 2006-2012 Jean-Philippe Lang
|
||||
http://www.redmine.org/
|
||||
|
||||
== 2012-06-18 v2.0.3
|
||||
|
||||
* Defect #10688: PDF export from Wiki - Problems with tables
|
||||
* Defect #11061: Cannot choose commit versions to view differences in Git/Mercurial repository view
|
||||
* Defect #11065: E-Mail submitted tickets: German umlauts in 'Subject' get malformed (ruby 1.8)
|
||||
* Defect #11098: Default priorities have the same position and can't be reordered
|
||||
* Defect #11105: <% content_for :header_tags do %> doesn't work inside hook
|
||||
* Defect #11112: REST API - custom fields in POST/PUT ignored for time_entries
|
||||
* Defect #11118: "Maximum file size" displayed on upload forms is incorrect
|
||||
* Defect #11124: Link to user is escaped in activity title
|
||||
* Defect #11133: Wiki-page section edit link can point to incorrect section
|
||||
* Defect #11160: SQL Error on time report if a custom field has multiple values for an entry
|
||||
* Defect #11170: Topics sort order is broken in Redmine 2.x
|
||||
* Defect #11178: Spent time sorted by date-descending order lists same-date entries in physical order (not-reverse)
|
||||
* Defect #11185: Redmine fails to delete a project with parent/child task
|
||||
* Feature #11162: Upgrade to Rails 3.2.6
|
||||
* Patch #11113: Small glitch in German localization
|
||||
|
||||
== 2012-06-05 v2.0.2
|
||||
|
||||
* Defect #11032: Project list is not shown when "For any event on the selected projects only..." is selected on user edit panel
|
||||
* Defect #11038: "Create and continue" should preserve project, issue and activity when logging time
|
||||
* Defect #11046: Redmine.pm does not support "bind as user" ldap authentication
|
||||
* Defect #11051: reposman.rb fails in 1.4.2 because of missing require for rubygems
|
||||
* Defect #11085: Wiki start page can't be changed
|
||||
* Feature #11084: Update Rails to 3.2.5
|
||||
|
||||
== 2012-05-28 v2.0.1
|
||||
|
||||
* Defect #10923: After creating a new Version Redmine jumps back to "Information"
|
||||
|
||||
@@ -366,12 +366,19 @@ sub is_member {
|
||||
);
|
||||
$sthldap->execute($auth_source_id);
|
||||
while (my @rowldap = $sthldap->fetchrow_array) {
|
||||
my $bind_as = $rowldap[3] ? $rowldap[3] : "";
|
||||
my $bind_pw = $rowldap[4] ? $rowldap[4] : "";
|
||||
if ($bind_as =~ m/\$login/) {
|
||||
# replace $login with $redmine_user and use $redmine_pass
|
||||
$bind_as =~ s/\$login/$redmine_user/g;
|
||||
$bind_pw = $redmine_pass
|
||||
}
|
||||
my $ldap = Authen::Simple::LDAP->new(
|
||||
host => ($rowldap[2] eq "1" || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]:$rowldap[1]" : $rowldap[0],
|
||||
port => $rowldap[1],
|
||||
basedn => $rowldap[5],
|
||||
binddn => $rowldap[3] ? $rowldap[3] : "",
|
||||
bindpw => $rowldap[4] ? $rowldap[4] : "",
|
||||
binddn => $bind_as,
|
||||
bindpw => $bind_pw,
|
||||
filter => "(".$rowldap[6]."=%s)"
|
||||
);
|
||||
my $method = $r->method;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
require 'optparse'
|
||||
require 'find'
|
||||
require 'etc'
|
||||
require 'rubygems'
|
||||
|
||||
Version = "1.4"
|
||||
SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem )
|
||||
|
||||
@@ -131,6 +131,15 @@ module ActiveRecord
|
||||
when 'lowest'
|
||||
move_to_bottom
|
||||
end
|
||||
reset_positions_in_list
|
||||
end
|
||||
|
||||
def reset_positions_in_list
|
||||
acts_as_list_class.where(scope_condition).reorder("#{position_column} ASC, id ASC").each_with_index do |item, i|
|
||||
unless item.send(position_column) == (i + 1)
|
||||
acts_as_list_class.update_all({position_column => (i + 1)}, {:id => item.id})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Removes the item from the list.
|
||||
@@ -209,7 +218,7 @@ module ActiveRecord
|
||||
def bottom_item(except = nil)
|
||||
conditions = scope_condition
|
||||
conditions = "#{conditions} AND #{self.class.primary_key} != #{except.id}" if except
|
||||
acts_as_list_class.find(:first, :conditions => conditions, :order => "#{position_column} DESC")
|
||||
acts_as_list_class.where(conditions).reorder("#{position_column} DESC").first
|
||||
end
|
||||
|
||||
# Forces item to assume the bottom position in the list.
|
||||
|
||||
@@ -283,6 +283,7 @@ class TCPDF
|
||||
@state ||= 0
|
||||
@tableborder ||= 0
|
||||
@tdbegin ||= false
|
||||
@tdtext ||= ''
|
||||
@tdwidth ||= 0
|
||||
@tdheight ||= 0
|
||||
@tdalign ||= "L"
|
||||
@@ -3510,28 +3511,12 @@ class TCPDF
|
||||
|
||||
else
|
||||
#Text
|
||||
if (@href)
|
||||
if (@tdbegin)
|
||||
element.gsub!(/[\t\r\n\f]/, "");
|
||||
@tdtext << element.gsub(/ /, " ");
|
||||
elsif (@href)
|
||||
element.gsub!(/[\t\r\n\f]/, "");
|
||||
addHtmlLink(@href, element, fill);
|
||||
elsif (@tdbegin)
|
||||
element.gsub!(/[\t\r\n\f]/, "");
|
||||
element.gsub!(/ /, " ");
|
||||
base_page = @page;
|
||||
base_x = @x;
|
||||
base_y = @y;
|
||||
|
||||
MultiCell(@tdwidth, @tdheight, unhtmlentities(element.strip), @tableborder, @tdalign, @tdfill, 1);
|
||||
tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1;
|
||||
if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page)
|
||||
@max_td_page[tr_end] = @page
|
||||
@max_td_y[tr_end] = @y
|
||||
elsif (@max_td_page[tr_end] == @page)
|
||||
@max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y)
|
||||
end
|
||||
|
||||
@page = base_page;
|
||||
@x = base_x + @tdwidth;
|
||||
@y = base_y;
|
||||
elsif (@pre_state == true and element.length > 0)
|
||||
Write(@lasth, unhtmlentities(element), '', fill);
|
||||
elsif (element.strip.length > 0)
|
||||
@@ -3825,6 +3810,7 @@ class TCPDF
|
||||
@x += 5;
|
||||
|
||||
when 'table'
|
||||
Ln();
|
||||
if @default_table_columns < @max_table_columns[@table_id]
|
||||
@table_columns = @max_table_columns[@table_id];
|
||||
else
|
||||
@@ -3921,6 +3907,11 @@ class TCPDF
|
||||
|
||||
when 'img'
|
||||
if (!attrs['src'].nil?)
|
||||
# Don't generates image inside table tag
|
||||
if (@tdbegin)
|
||||
@tdtext << attrs['src'];
|
||||
return
|
||||
end
|
||||
# Only generates image include a pdf if RMagick is avalaible
|
||||
unless Object.const_defined?(:Magick)
|
||||
Write(@lasth, attrs['src'], '', fill);
|
||||
@@ -4079,6 +4070,23 @@ class TCPDF
|
||||
Ln();
|
||||
|
||||
when 'td','th'
|
||||
base_page = @page;
|
||||
base_x = @x;
|
||||
base_y = @y;
|
||||
|
||||
MultiCell(@tdwidth, @tdheight, unhtmlentities(@tdtext.strip), @tableborder, @tdalign, @tdfill, 1);
|
||||
tr_end = @t_cells[@table_id][@tr_id][@td_id]['j1'] + 1;
|
||||
if @max_td_page[tr_end].nil? or (@max_td_page[tr_end] < @page)
|
||||
@max_td_page[tr_end] = @page
|
||||
@max_td_y[tr_end] = @y
|
||||
elsif (@max_td_page[tr_end] == @page)
|
||||
@max_td_y[tr_end] = @y if @max_td_y[tr_end].nil? or (@max_td_y[tr_end] < @y)
|
||||
end
|
||||
|
||||
@page = base_page;
|
||||
@x = base_x + @tdwidth;
|
||||
@y = base_y;
|
||||
@tdtext = '';
|
||||
@tdbegin = false;
|
||||
@tdwidth = 0;
|
||||
@tdheight = 0;
|
||||
@@ -4126,7 +4134,6 @@ class TCPDF
|
||||
@l_margin -= 5;
|
||||
@r_margin -= 5;
|
||||
@tableborder=0;
|
||||
Ln();
|
||||
@table_id += 1;
|
||||
|
||||
when 'strong'
|
||||
|
||||
@@ -138,21 +138,21 @@ module Redmine
|
||||
# Add list and boolean custom fields as available criteria
|
||||
custom_fields = (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields)
|
||||
custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = #{Issue.table_name}.id)",
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = #{Issue.table_name}.id ORDER BY c.value LIMIT 1)",
|
||||
:format => cf.field_format,
|
||||
:label => cf.name}
|
||||
end if @project
|
||||
|
||||
# Add list and boolean time entry custom fields
|
||||
TimeEntryCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)",
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id ORDER BY c.value LIMIT 1)",
|
||||
:format => cf.field_format,
|
||||
:label => cf.name}
|
||||
end
|
||||
|
||||
# Add list and boolean time entry activity custom fields
|
||||
TimeEntryActivityCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id)",
|
||||
@available_criteria["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id ORDER BY c.value LIMIT 1)",
|
||||
:format => cf.field_format,
|
||||
:label => cf.name}
|
||||
end
|
||||
|
||||
@@ -107,7 +107,13 @@ module Redmine
|
||||
#
|
||||
def self.render_on(hook, options={})
|
||||
define_method hook do |context|
|
||||
context[:controller].send(:render_to_string, {:locals => context}.merge(options))
|
||||
if context[:hook_caller].respond_to?(:render)
|
||||
context[:hook_caller].send(:render, {:locals => context}.merge(options))
|
||||
elsif context[:controller].is_a?(ActionController::Base)
|
||||
context[:controller].send(:render_to_string, {:locals => context}.merge(options))
|
||||
else
|
||||
raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -138,14 +144,15 @@ module Redmine
|
||||
# * project => current project
|
||||
# * request => Request instance
|
||||
# * controller => current Controller instance
|
||||
# * hook_caller => object that called the hook
|
||||
#
|
||||
module Helper
|
||||
def call_hook(hook, context={})
|
||||
if is_a?(ActionController::Base)
|
||||
default_context = {:controller => self, :project => @project, :request => request}
|
||||
default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self}
|
||||
Redmine::Hook.call_hook(hook, default_context.merge(context))
|
||||
else
|
||||
default_context = { :project => @project }
|
||||
default_context = { :project => @project, :hook_caller => self }
|
||||
default_context[:controller] = controller if respond_to?(:controller)
|
||||
default_context[:request] = request if respond_to?(:request)
|
||||
Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe
|
||||
|
||||
@@ -4,7 +4,7 @@ module Redmine
|
||||
module VERSION #:nodoc:
|
||||
MAJOR = 2
|
||||
MINOR = 0
|
||||
TINY = 1
|
||||
TINY = 3
|
||||
|
||||
# Branch values:
|
||||
# * official release: nil
|
||||
|
||||
@@ -69,7 +69,7 @@ module Redmine
|
||||
l = 1
|
||||
started = false
|
||||
ended = false
|
||||
text.scan(/(((?:.*?)(\A|\r?\n\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level|
|
||||
text.scan(/(((?:.*?)(\A|\r?\n\s*\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))? (.*?)$)|.*)/m).each do |all, content, lf, heading, level|
|
||||
if heading.nil?
|
||||
if ended
|
||||
after << all
|
||||
|
||||
@@ -163,7 +163,7 @@ namespace :redmine do
|
||||
set_inheritance_column :none
|
||||
|
||||
# ticket changes: only migrate status changes and comments
|
||||
has_many :changes, :class_name => "TracTicketChange", :foreign_key => :ticket
|
||||
has_many :ticket_changes, :class_name => "TracTicketChange", :foreign_key => :ticket
|
||||
has_many :customs, :class_name => "TracTicketCustom", :foreign_key => :ticket
|
||||
|
||||
def attachments
|
||||
@@ -487,7 +487,7 @@ namespace :redmine do
|
||||
end
|
||||
|
||||
# Comments and status/resolution changes
|
||||
ticket.changes.group_by(&:time).each do |time, changeset|
|
||||
ticket.ticket_changes.group_by(&:time).each do |time, changeset|
|
||||
status_change = changeset.select {|change| change.field == 'status'}.first
|
||||
resolution_change = changeset.select {|change| change.field == 'resolution'}.first
|
||||
comment_change = changeset.select {|change| change.field == 'comment'}.first
|
||||
|
||||
@@ -4,7 +4,7 @@ table.revision-info td {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
div.revision-graph { position: absolute; }
|
||||
div.revision-graph { position: absolute; min-width: 1px; }
|
||||
|
||||
div.changeset-changes ul { margin: 0; padding: 0; }
|
||||
div.changeset-changes ul > ul { margin-left: 18px; padding: 0; }
|
||||
|
||||
11
test/fixtures/mail_handler/subject_as_iso-8859-1.eml
vendored
Normal file
11
test/fixtures/mail_handler/subject_as_iso-8859-1.eml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
Content-Type: application/ms-tnef; name="winmail.dat"
|
||||
Content-Transfer-Encoding: binary
|
||||
From: John Smith <JSmith@somenet.foo>
|
||||
To: "redmine@somenet.foo" <redmine@somenet.foo>
|
||||
Subject: =?iso-8859-1?Q?Testmail_from_Webmail:_=E4_=F6_=FC...?=
|
||||
Date: Fri, 1 Jun 2012 14:39:38 +0200
|
||||
Message-ID: <87C31D42249DD0489D1A1444E3232DD7019D6183@foo.bar>
|
||||
Accept-Language: de-CH, en-US
|
||||
Content-Language: de-CH
|
||||
|
||||
Fixture
|
||||
@@ -73,13 +73,19 @@ class ActivitiesControllerTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
def test_user_index
|
||||
@request.session[:user_id] = 1
|
||||
get :index, :user_id => 2
|
||||
assert_response :success
|
||||
assert_template 'index'
|
||||
assert_not_nil assigns(:events_by_day)
|
||||
|
||||
assert_select 'h2 a[href=/users/2]', :text => 'John Smith'
|
||||
|
||||
i1 = Issue.find(1)
|
||||
d1 = User.find(1).time_to_date(i1.created_on)
|
||||
|
||||
assert_tag :tag => "h3",
|
||||
:content => /#{3.day.ago.to_date.day}/,
|
||||
:content => /#{d1.day}/,
|
||||
:sibling => { :tag => "dl",
|
||||
:child => { :tag => "dt",
|
||||
:attributes => { :class => /issue/ },
|
||||
|
||||
@@ -55,6 +55,20 @@ class BoardsControllerTest < ActionController::TestCase
|
||||
assert_not_nil assigns(:topics)
|
||||
end
|
||||
|
||||
def test_show_should_display_sticky_messages_first
|
||||
Message.update_all(:sticky => 0)
|
||||
Message.update_all({:sticky => 1}, {:id => 1})
|
||||
|
||||
get :show, :project_id => 1, :id => 1
|
||||
assert_response :success
|
||||
|
||||
topics = assigns(:topics)
|
||||
assert_not_nil topics
|
||||
assert topics.size > 1, "topics size was #{topics.size}"
|
||||
assert topics.first.sticky?
|
||||
assert topics.first.updated_on < topics.second.updated_on
|
||||
end
|
||||
|
||||
def test_show_with_permission_should_display_the_new_message_form
|
||||
@request.session[:user_id] = 2
|
||||
get :show, :project_id => 1, :id => 1
|
||||
|
||||
@@ -87,6 +87,16 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
end
|
||||
|
||||
if File.directory?(REPOSITORY_PATH)
|
||||
## Ruby uses ANSI api to fork a process on Windows.
|
||||
## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
|
||||
## and these are incompatible with ASCII.
|
||||
## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
|
||||
## http://code.google.com/p/msysgit/issues/detail?id=80
|
||||
## So, Latin-1 path tests fail on Japanese Windows
|
||||
WINDOWS_PASS = (Redmine::Platform.mswin? &&
|
||||
Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
|
||||
WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
|
||||
|
||||
def test_get_new
|
||||
@request.session[:user_id] = 1
|
||||
@project.repository.destroy
|
||||
@@ -214,6 +224,8 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
def test_entry_show_latin_1
|
||||
if @ruby19_non_utf8_pass
|
||||
puts_ruby19_non_utf8_pass()
|
||||
elsif WINDOWS_PASS
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
@@ -435,6 +447,8 @@ class RepositoriesGitControllerTest < ActionController::TestCase
|
||||
def test_annotate_latin_1
|
||||
if @ruby19_non_utf8_pass
|
||||
puts_ruby19_non_utf8_pass()
|
||||
elsif WINDOWS_PASS
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
|
||||
@@ -80,6 +80,16 @@ class TimeEntryReportsControllerTest < ActionController::TestCase
|
||||
assert_equal "162.90", "%.2f" % assigns(:report).total_hours
|
||||
end
|
||||
|
||||
def test_report_custom_field_criteria_with_multiple_values
|
||||
field = TimeEntryCustomField.create!(:name => 'multi', :field_format => 'list', :possible_values => ['value1', 'value2'])
|
||||
entry = TimeEntry.create!(:project => Project.find(1), :hours => 1, :activity_id => 10, :user => User.find(2), :spent_on => Date.today)
|
||||
CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value1')
|
||||
CustomValue.create!(:customized => entry, :custom_field => field, :value => 'value2')
|
||||
|
||||
get :report, :project_id => 1, :columns => 'day', :criteria => ["cf_#{field.id}"]
|
||||
assert_response :success
|
||||
end
|
||||
|
||||
def test_report_one_day
|
||||
get :report, :project_id => 1, :columns => 'day', :from => "2007-03-23", :to => "2007-03-23", :criteria => ["member", "activity"]
|
||||
assert_response :success
|
||||
|
||||
@@ -44,6 +44,7 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
# Default activity selected
|
||||
assert_tag :tag => 'option', :attributes => { :selected => 'selected' },
|
||||
:content => 'Development'
|
||||
assert_select 'input[name=project_id][value=1]'
|
||||
end
|
||||
|
||||
def test_get_new_should_only_show_active_time_entry_activities
|
||||
@@ -61,6 +62,18 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
assert_response :success
|
||||
assert_template 'new'
|
||||
assert_tag 'select', :attributes => {:name => 'time_entry[project_id]'}
|
||||
assert_select 'input[name=project_id]', 0
|
||||
end
|
||||
|
||||
def test_new_without_project_should_prefill_the_form
|
||||
@request.session[:user_id] = 3
|
||||
get :new, :time_entry => {:project_id => '1'}
|
||||
assert_response :success
|
||||
assert_template 'new'
|
||||
assert_select 'select[name=?]', 'time_entry[project_id]' do
|
||||
assert_select 'option[value=1][selected=selected]'
|
||||
end
|
||||
assert_select 'input[name=project_id]', 0
|
||||
end
|
||||
|
||||
def test_new_without_project_should_deny_without_permission
|
||||
@@ -144,7 +157,7 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
:spent_on => '2008-03-14',
|
||||
:hours => '7.3'},
|
||||
:continue => '1'
|
||||
assert_redirected_to '/projects/ecookbook/time_entries/new'
|
||||
assert_redirected_to '/projects/ecookbook/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D='
|
||||
end
|
||||
|
||||
def test_create_and_continue_with_issue_id
|
||||
@@ -155,7 +168,7 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
:spent_on => '2008-03-14',
|
||||
:hours => '7.3'},
|
||||
:continue => '1'
|
||||
assert_redirected_to '/projects/ecookbook/issues/1/time_entries/new'
|
||||
assert_redirected_to '/projects/ecookbook/issues/1/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=1'
|
||||
end
|
||||
|
||||
def test_create_and_continue_without_project
|
||||
@@ -167,7 +180,7 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
:hours => '7.3'},
|
||||
:continue => '1'
|
||||
|
||||
assert_redirected_to '/time_entries/new'
|
||||
assert_redirected_to '/time_entries/new?time_entry%5Bactivity_id%5D=11&time_entry%5Bissue_id%5D=&time_entry%5Bproject_id%5D=1'
|
||||
end
|
||||
|
||||
def test_create_without_log_time_permission_should_be_denied
|
||||
@@ -555,6 +568,20 @@ class TimelogControllerTest < ActionController::TestCase
|
||||
:attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'}
|
||||
end
|
||||
|
||||
def test_index_should_sort_by_spent_on_and_created_on
|
||||
t1 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:00:00', :activity_id => 10)
|
||||
t2 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-16', :created_on => '2012-06-16 20:05:00', :activity_id => 10)
|
||||
t3 = TimeEntry.create!(:user => User.find(1), :project => Project.find(1), :hours => 1, :spent_on => '2012-06-15', :created_on => '2012-06-16 20:10:00', :activity_id => 10)
|
||||
|
||||
get :index, :project_id => 1, :from => '2012-06-15', :to => '2012-06-16'
|
||||
assert_response :success
|
||||
assert_equal [t2, t1, t3], assigns(:entries)
|
||||
|
||||
get :index, :project_id => 1, :from => '2012-06-15', :to => '2012-06-16', :sort => 'spent_on'
|
||||
assert_response :success
|
||||
assert_equal [t3, t1, t2], assigns(:entries)
|
||||
end
|
||||
|
||||
def test_index_atom_feed
|
||||
get :index, :project_id => 1, :format => 'atom'
|
||||
assert_response :success
|
||||
|
||||
@@ -311,6 +311,29 @@ class UsersControllerTest < ActionController::TestCase
|
||||
assert u.check_password?('newpass')
|
||||
end
|
||||
|
||||
def test_update_notified_project
|
||||
get :edit, :id => 2
|
||||
assert_response :success
|
||||
assert_template 'edit'
|
||||
u = User.find(2)
|
||||
assert_equal [1, 2, 5], u.projects.collect{|p| p.id}.sort
|
||||
assert_equal [1, 2, 5], u.notified_projects_ids.sort
|
||||
assert_tag :tag => 'input',
|
||||
:attributes => {
|
||||
:id => 'notified_project_ids_',
|
||||
:value => 1,
|
||||
}
|
||||
assert_equal 'all', u.mail_notification
|
||||
put :update, :id => 2,
|
||||
:user => {
|
||||
:mail_notification => 'selected',
|
||||
},
|
||||
:notified_project_ids => [1, 2]
|
||||
u = User.find(2)
|
||||
assert_equal 'selected', u.mail_notification
|
||||
assert_equal [1, 2], u.notified_projects_ids.sort
|
||||
end
|
||||
|
||||
def test_destroy
|
||||
assert_difference 'User.count', -1 do
|
||||
delete :destroy, :id => 2
|
||||
|
||||
@@ -79,6 +79,21 @@ class ApiTest::TimeEntriesTest < ActionController::IntegrationTest
|
||||
assert_equal 3.5, entry.hours
|
||||
assert_equal TimeEntryActivity.find(11), entry.activity
|
||||
end
|
||||
|
||||
should "accept custom fields" do
|
||||
field = TimeEntryCustomField.create!(:name => 'Test', :field_format => 'string')
|
||||
|
||||
assert_difference 'TimeEntry.count' do
|
||||
post '/time_entries.xml', {:time_entry => {
|
||||
:issue_id => '1', :spent_on => '2010-12-02', :hours => '3.5', :activity_id => '11', :custom_fields => [{:id => field.id.to_s, :value => 'accepted'}]
|
||||
}}, credentials('jsmith')
|
||||
end
|
||||
assert_response :created
|
||||
assert_equal 'application/xml', @response.content_type
|
||||
|
||||
entry = TimeEntry.first(:order => 'id DESC')
|
||||
assert_equal 'accepted', entry.custom_field_value(field)
|
||||
end
|
||||
end
|
||||
|
||||
context "with project_id" do
|
||||
|
||||
@@ -35,6 +35,17 @@ class MenuManagerTest < ActionController::IntegrationTest
|
||||
end
|
||||
end
|
||||
|
||||
class ContentForInsideHook < Redmine::Hook::ViewListener
|
||||
render_on :view_welcome_index_left, :inline => <<-VIEW
|
||||
<% content_for :header_tags do %>
|
||||
<%= javascript_include_tag 'test_plugin.js', :plugin => 'test_plugin' %>
|
||||
<%= stylesheet_link_tag 'test_plugin.css', :plugin => 'test_plugin' %>
|
||||
<% end %>
|
||||
|
||||
<p>ContentForInsideHook content</p>
|
||||
VIEW
|
||||
end
|
||||
|
||||
def setup
|
||||
Redmine::Hook.clear_listeners
|
||||
end
|
||||
@@ -64,4 +75,16 @@ class MenuManagerTest < ActionController::IntegrationTest
|
||||
assert_select 'div#main'
|
||||
assert_select 'div#main.nosidebar', 0
|
||||
end
|
||||
|
||||
def test_hook_with_content_for_should_append_content
|
||||
Redmine::Hook.add_listener(ContentForInsideHook)
|
||||
|
||||
get '/'
|
||||
assert_response :success
|
||||
assert_select 'p', :text => 'ContentForInsideHook content'
|
||||
assert_select 'head' do
|
||||
assert_select 'script[src=/plugin_assets/test_plugin/javascripts/test_plugin.js]'
|
||||
assert_select 'link[href=/plugin_assets/test_plugin/stylesheets/test_plugin.css]'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -97,7 +97,7 @@ class GroupTest < ActiveSupport::TestCase
|
||||
|
||||
def test_roles_removed_when_removing_user_from_group
|
||||
assert User.find(8).member_of?(Project.find(5))
|
||||
User.find(8).groups.clear
|
||||
User.find(8).groups = []
|
||||
assert !User.find(8).member_of?(Project.find(5))
|
||||
end
|
||||
|
||||
|
||||
@@ -34,5 +34,30 @@ class IssuePriorityTest < ActiveSupport::TestCase
|
||||
def test_option_name
|
||||
assert_equal :enumeration_issue_priorities, IssuePriority.new.option_name
|
||||
end
|
||||
end
|
||||
|
||||
def test_should_be_created_at_last_position
|
||||
IssuePriority.delete_all
|
||||
|
||||
priorities = [1, 2, 3].map {|i| IssuePriority.create!(:name => "P#{i}")}
|
||||
assert_equal [1, 2, 3], priorities.map(&:position)
|
||||
end
|
||||
|
||||
def test_reset_positions_in_list_should_set_sequential_positions
|
||||
IssuePriority.delete_all
|
||||
|
||||
priorities = [1, 2, 3].map {|i| IssuePriority.create!(:name => "P#{i}")}
|
||||
priorities[0].update_attribute :position, 4
|
||||
priorities[1].update_attribute :position, 2
|
||||
priorities[2].update_attribute :position, 7
|
||||
assert_equal [4, 2, 7], priorities.map(&:reload).map(&:position)
|
||||
|
||||
priorities[0].reset_positions_in_list
|
||||
assert_equal [2, 1, 3], priorities.map(&:reload).map(&:position)
|
||||
end
|
||||
|
||||
def test_moving_in_list_should_reset_positions
|
||||
priority = IssuePriority.first
|
||||
priority.expects(:reset_positions_in_list).once
|
||||
priority.move_to = 'higher'
|
||||
end
|
||||
end
|
||||
|
||||
@@ -761,6 +761,30 @@ class IssueTest < ActiveSupport::TestCase
|
||||
assert_nil TimeEntry.find_by_issue_id(1)
|
||||
end
|
||||
|
||||
def test_destroying_a_deleted_issue_should_not_raise_an_error
|
||||
issue = Issue.find(1)
|
||||
Issue.find(1).destroy
|
||||
|
||||
assert_nothing_raised do
|
||||
assert_no_difference 'Issue.count' do
|
||||
issue.destroy
|
||||
end
|
||||
assert issue.destroyed?
|
||||
end
|
||||
end
|
||||
|
||||
def test_destroying_a_stale_issue_should_not_raise_an_error
|
||||
issue = Issue.find(1)
|
||||
Issue.find(1).update_attribute :subject, "Updated"
|
||||
|
||||
assert_nothing_raised do
|
||||
assert_difference 'Issue.count', -1 do
|
||||
issue.destroy
|
||||
end
|
||||
assert issue.destroyed?
|
||||
end
|
||||
end
|
||||
|
||||
def test_blocked
|
||||
blocked_issue = Issue.find(9)
|
||||
blocking_issue = Issue.find(10)
|
||||
|
||||
@@ -89,7 +89,7 @@ class Redmine::Hook::ManagerTest < ActionView::TestCase
|
||||
|
||||
def test_call_hook_with_context
|
||||
@hook_module.add_listener(TestHook3)
|
||||
assert_equal ['Context keys: bar, controller, foo, project, request.'],
|
||||
assert_equal ['Context keys: bar, controller, foo, hook_caller, project, request.'],
|
||||
hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
|
||||
end
|
||||
|
||||
|
||||
@@ -121,7 +121,8 @@ class Redmine::I18nTest < ActiveSupport::TestCase
|
||||
valid_languages.each do |lang|
|
||||
set_language_if_valid lang
|
||||
assert_nothing_raised "#{lang} failure" do
|
||||
number_to_human_size(1024*1024*4)
|
||||
size = number_to_human_size(257024)
|
||||
assert_match /251/, size
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,8 +13,12 @@ begin
|
||||
## Ruby uses ANSI api to fork a process on Windows.
|
||||
## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
|
||||
## and these are incompatible with ASCII.
|
||||
# WINDOWS_PASS = Redmine::Platform.mswin?
|
||||
WINDOWS_PASS = false
|
||||
## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
|
||||
## http://code.google.com/p/msysgit/issues/detail?id=80
|
||||
## So, Latin-1 path tests fail on Japanese Windows
|
||||
WINDOWS_PASS = (Redmine::Platform.mswin? &&
|
||||
Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
|
||||
WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
|
||||
|
||||
## Git, Mercurial and CVS path encodings are binary.
|
||||
## Subversion supports URL encoding for path.
|
||||
@@ -391,7 +395,7 @@ begin
|
||||
|
||||
def test_latin_1_path
|
||||
if WINDOWS_PASS
|
||||
#
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
@@ -453,7 +457,7 @@ begin
|
||||
|
||||
def test_entries_latin_1_dir
|
||||
if WINDOWS_PASS
|
||||
#
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
|
||||
@@ -394,6 +394,31 @@ Nulla nunc nisi, egestas in ornare vel, posuere ac libero."]
|
||||
@formatter.new(text).update_section(3, replacement)
|
||||
end
|
||||
|
||||
def test_get_section_should_support_lines_with_spaces_before_heading
|
||||
# the lines after Content 2 and Heading 4 contain a space
|
||||
text = <<-STR
|
||||
h1. Heading 1
|
||||
|
||||
Content 1
|
||||
|
||||
h1. Heading 2
|
||||
|
||||
Content 2
|
||||
|
||||
h1. Heading 3
|
||||
|
||||
Content 3
|
||||
|
||||
h1. Heading 4
|
||||
|
||||
Content 4
|
||||
STR
|
||||
|
||||
[1, 2, 3, 4].each do |index|
|
||||
assert_match /\Ah1. Heading #{index}.+Content #{index}/m, @formatter.new(text).get_section(index).first
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_html_output(to_test, expect_paragraph = true)
|
||||
|
||||
@@ -347,6 +347,15 @@ class MailHandlerTest < ActiveSupport::TestCase
|
||||
assert_equal 'caaf384198bcbc9563ab5c058acd73cd', attachment.digest
|
||||
end
|
||||
|
||||
def test_add_issue_with_iso_8859_1_subject
|
||||
issue = submit_email(
|
||||
'subject_as_iso-8859-1.eml',
|
||||
:issue => {:project => 'ecookbook'}
|
||||
)
|
||||
assert_kind_of Issue, issue
|
||||
assert_equal 'Testmail from Webmail: ä ö ü...', issue.subject
|
||||
end
|
||||
|
||||
def test_should_ignore_emails_from_locked_users
|
||||
User.find(2).lock!
|
||||
|
||||
|
||||
@@ -190,6 +190,18 @@ class ProjectTest < ActiveSupport::TestCase
|
||||
assert_nil Issue.first(:conditions => {:project_id => @ecookbook.id})
|
||||
end
|
||||
|
||||
def test_destroy_should_destroy_subtasks
|
||||
issues = (0..2).to_a.map {Issue.create!(:project_id => 1, :tracker_id => 1, :author_id => 1, :subject => 'test')}
|
||||
issues[0].update_attribute :parent_issue_id, issues[1].id
|
||||
issues[2].update_attribute :parent_issue_id, issues[1].id
|
||||
assert_equal 2, issues[1].children.count
|
||||
|
||||
assert_nothing_raised do
|
||||
Project.find(1).destroy
|
||||
end
|
||||
assert Issue.find_all_by_id(issues.map(&:id)).empty?
|
||||
end
|
||||
|
||||
def test_destroying_root_projects_should_clear_data
|
||||
Project.roots.each do |root|
|
||||
root.destroy
|
||||
|
||||
@@ -67,7 +67,7 @@ class RepositoryBazaarTest < ActiveSupport::TestCase
|
||||
@project.reload
|
||||
|
||||
assert_equal NUM_REV, @repository.changesets.count
|
||||
assert_equal 9, @repository.changes.count
|
||||
assert_equal 9, @repository.filechanges.count
|
||||
assert_equal 'Initial import', @repository.changesets.find_by_revision('1').comments
|
||||
end
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ class RepositoryCvsTest < ActiveSupport::TestCase
|
||||
@project.reload
|
||||
|
||||
assert_equal CHANGESETS_NUM, @repository.changesets.count
|
||||
assert_equal 16, @repository.changes.count
|
||||
assert_equal 16, @repository.filechanges.count
|
||||
assert_not_nil @repository.changesets.find_by_comments('Two files changed')
|
||||
|
||||
r2 = @repository.changesets.find_by_revision('2')
|
||||
|
||||
@@ -68,7 +68,7 @@ class RepositoryDarcsTest < ActiveSupport::TestCase
|
||||
@project.reload
|
||||
|
||||
assert_equal NUM_REV, @repository.changesets.count
|
||||
assert_equal 13, @repository.changes.count
|
||||
assert_equal 13, @repository.filechanges.count
|
||||
assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments
|
||||
end
|
||||
|
||||
|
||||
@@ -62,11 +62,11 @@ class RepositoryFilesystemTest < ActiveSupport::TestCase
|
||||
if File.directory?(REPOSITORY_PATH)
|
||||
def test_fetch_changesets
|
||||
assert_equal 0, @repository.changesets.count
|
||||
assert_equal 0, @repository.changes.count
|
||||
assert_equal 0, @repository.filechanges.count
|
||||
@repository.fetch_changesets
|
||||
@project.reload
|
||||
assert_equal 0, @repository.changesets.count
|
||||
assert_equal 0, @repository.changes.count
|
||||
assert_equal 0, @repository.filechanges.count
|
||||
end
|
||||
|
||||
def test_entries
|
||||
|
||||
@@ -31,12 +31,6 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
FELIX_HEX = "Felix Sch\xC3\xA4fer"
|
||||
CHAR_1_HEX = "\xc3\x9c"
|
||||
|
||||
## Ruby uses ANSI api to fork a process on Windows.
|
||||
## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
|
||||
## and these are incompatible with ASCII.
|
||||
# WINDOWS_PASS = Redmine::Platform.mswin?
|
||||
WINDOWS_PASS = false
|
||||
|
||||
## Git, Mercurial and CVS path encodings are binary.
|
||||
## Subversion supports URL encoding for path.
|
||||
## Redmine Mercurial adapter and extension use URL encoding.
|
||||
@@ -85,6 +79,16 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
if File.directory?(REPOSITORY_PATH)
|
||||
## Ruby uses ANSI api to fork a process on Windows.
|
||||
## Japanese Shift_JIS and Traditional Chinese Big5 have 0x5c(backslash) problem
|
||||
## and these are incompatible with ASCII.
|
||||
## Git for Windows (msysGit) changed internal API from ANSI to Unicode in 1.7.10
|
||||
## http://code.google.com/p/msysgit/issues/detail?id=80
|
||||
## So, Latin-1 path tests fail on Japanese Windows
|
||||
WINDOWS_PASS = (Redmine::Platform.mswin? &&
|
||||
Redmine::Scm::Adapters::GitAdapter.client_version_above?([1, 7, 10]))
|
||||
WINDOWS_SKIP_STR = "TODO: This test fails in Git for Windows above 1.7.10"
|
||||
|
||||
def test_scm_available
|
||||
klass = Repository::Git
|
||||
assert_equal "Git", klass.scm_name
|
||||
@@ -101,7 +105,7 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
@project.reload
|
||||
|
||||
assert_equal NUM_REV, @repository.changesets.count
|
||||
assert_equal 39, @repository.changes.count
|
||||
assert_equal 39, @repository.filechanges.count
|
||||
|
||||
commit = @repository.changesets.find_by_revision("7234cb2750b63f47bff735edc50a1c0a433c2518")
|
||||
assert_equal "7234cb2750b63f47bff735edc50a1c0a433c2518", commit.scmid
|
||||
@@ -111,8 +115,8 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
# TODO: add a commit with commit time <> author time to the test repository
|
||||
assert_equal "2007-12-14 09:22:52".to_time, commit.committed_on
|
||||
assert_equal "2007-12-14".to_date, commit.commit_date
|
||||
assert_equal 3, commit.changes.count
|
||||
change = commit.changes.sort_by(&:path).first
|
||||
assert_equal 3, commit.filechanges.count
|
||||
change = commit.filechanges.sort_by(&:path).first
|
||||
assert_equal "README", change.path
|
||||
assert_equal nil, change.from_path
|
||||
assert_equal "A", change.action
|
||||
@@ -400,7 +404,9 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
'61b685fbe55ab05b5ac68402d5720c1a6ac973d1',
|
||||
], changesets.collect(&:revision)
|
||||
|
||||
if JRUBY_SKIP
|
||||
if WINDOWS_PASS
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
# latin-1 encoding path
|
||||
@@ -421,7 +427,7 @@ class RepositoryGitTest < ActiveSupport::TestCase
|
||||
|
||||
def test_latest_changesets_latin_1_dir
|
||||
if WINDOWS_PASS
|
||||
#
|
||||
puts WINDOWS_SKIP_STR
|
||||
elsif JRUBY_SKIP
|
||||
puts JRUBY_SKIP_STR
|
||||
else
|
||||
|
||||
@@ -86,7 +86,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
|
||||
@repository.fetch_changesets
|
||||
@project.reload
|
||||
assert_equal NUM_REV, @repository.changesets.count
|
||||
assert_equal 46, @repository.changes.count
|
||||
assert_equal 46, @repository.filechanges.count
|
||||
assert_equal "Initial import.\nThe repository contains 3 files.",
|
||||
@repository.changesets.find_by_revision('0').comments
|
||||
end
|
||||
@@ -214,7 +214,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
|
||||
|
||||
cs1 = @repository.changesets.find_by_revision('13')
|
||||
assert_not_nil cs1
|
||||
c1 = cs1.changes.sort_by(&:path)
|
||||
c1 = cs1.filechanges.sort_by(&:path)
|
||||
assert_equal 2, c1.size
|
||||
|
||||
assert_equal 'A', c1[0].action
|
||||
@@ -227,7 +227,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
|
||||
assert_equal '/sql_escape/underscore_dir/understrike_file.txt', c1[1].from_path
|
||||
|
||||
cs2 = @repository.changesets.find_by_revision('15')
|
||||
c2 = cs2.changes
|
||||
c2 = cs2.filechanges
|
||||
assert_equal 1, c2.size
|
||||
|
||||
assert_equal 'A', c2[0].action
|
||||
@@ -236,7 +236,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase
|
||||
assert_equal '933ca60293d7', c2[0].from_revision
|
||||
|
||||
cs3 = @repository.changesets.find_by_revision('19')
|
||||
c3 = cs3.changes
|
||||
c3 = cs3.filechanges
|
||||
assert_equal 1, c3.size
|
||||
assert_equal 'A', c3[0].action
|
||||
assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user