Compare commits

..

11 Commits
0.8.1 ... 0.8.2

Author SHA1 Message Date
Jean-Philippe Lang
908dcc4eb4 tagged version 0.8.2
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/0.8.2@2570 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-08 14:33:29 +00:00
Jean-Philippe Lang
20bdba13cf Updates for 0.8.2 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2560 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-07 12:07:06 +00:00
Jean-Philippe Lang
46c0d72782 Merged r2259 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2559 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-07 12:02:08 +00:00
Jean-Philippe Lang
36b5d4f6af Backported r2429, r2430, r248 to r2491 and r2522 from trunk (request and controller objects added to the hooks by default.).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2558 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-07 11:43:38 +00:00
Jean-Philippe Lang
b366375e7e Merged r2553 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2557 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-07 11:22:56 +00:00
Jean-Philippe Lang
629c106a46 Merged r2515, r2516, r2527, r2534, r2555 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2556 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-07 11:17:23 +00:00
Eric Davis
f19ae06a72 Merged r2428 from trunk
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2548 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-04 00:03:06 +00:00
Jean-Philippe Lang
69b99aa518 Merged r2520 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2521 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-23 17:36:32 +00:00
Jean-Philippe Lang
cb5d0c469d Merged r2487, r2488 and r2507 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2514 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-22 10:00:25 +00:00
Jean-Philippe Lang
57d10ed893 Merged r2262, r2341 and r2486 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2513 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-21 19:29:33 +00:00
Jean-Philippe Lang
28e4ff8957 Merged r2426 and r2484 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2512 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-21 19:22:31 +00:00
26 changed files with 341 additions and 51 deletions

View File

@@ -75,7 +75,11 @@ class UsersController < ApplicationController
@user.admin = params[:user][:admin] if params[:user][:admin]
@user.login = params[:user][:login] if params[:user][:login]
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id
if @user.update_attributes(params[:user])
@user.attributes = params[:user]
# Was the account actived ? (do it before User#save clears the change)
was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE])
if @user.save
Mailer.deliver_account_activated(@user) if was_activated
flash[:notice] = l(:notice_successful_update)
# Give a string to redirect_to otherwise it would use status param as the response code
redirect_to(url_for(:action => 'list', :status => params[:status], :page => params[:page]))

View File

@@ -487,11 +487,11 @@ module ApplicationHelper
full_messages = []
object.errors.each do |attr, msg|
next if msg.nil?
msg = msg.first if msg.is_a? Array
msg = [msg] unless msg.is_a?(Array)
if attr == "base"
full_messages << l(msg)
full_messages << l(*msg)
else
full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(*msg) unless attr == "custom_values"
end
end
# retrieve custom values error messages
@@ -499,8 +499,8 @@ module ApplicationHelper
object.custom_values.each do |v|
v.errors.each do |attr, msg|
next if msg.nil?
msg = msg.first if msg.is_a? Array
full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
msg = [msg] unless msg.is_a?(Array)
full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(*msg)
end
end
end

View File

@@ -40,7 +40,7 @@ class MailHandler < ActionMailer::Base
# Processes incoming emails
def receive(email)
@email = email
@user = User.active.find(:first, :conditions => ["LOWER(mail) = ?", email.from.first.to_s.strip.downcase])
@user = User.active.find(:first, :conditions => ["LOWER(mail) = ?", email.from.to_a.first.to_s.strip.downcase])
unless @user
# Unknown user => the email is ignored
# TODO: ability to create the user's account
@@ -163,10 +163,17 @@ class MailHandler < ActionMailer::Base
end
def get_keyword(attr, options={})
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body =~ /^#{attr}:[ \t]*(.+)$/i
$1.strip
elsif !@@handler_options[:issue][attr].blank?
@@handler_options[:issue][attr]
@keywords ||= {}
if @keywords.has_key?(attr)
@keywords[attr]
else
@keywords[attr] = begin
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}:[ \t]*(.+)\s*$/i, '')
$1.strip
elsif !@@handler_options[:issue][attr].blank?
@@handler_options[:issue][attr]
end
end
end
end
@@ -188,5 +195,6 @@ class MailHandler < ActionMailer::Base
@plain_text_body = plain_text_part.body.to_s
end
@plain_text_body.strip!
@plain_text_body
end
end

View File

@@ -22,6 +22,12 @@ class Mailer < ActionMailer::Base
include ActionController::UrlWriter
def self.default_url_options
h = Setting.host_name
h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank?
{ :host => h, :protocol => Setting.protocol }
end
def issue_add(issue)
redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id,
@@ -127,6 +133,15 @@ class Mailer < ActionMailer::Base
:url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
end
# A registered user's account was activated by an administrator
def account_activated(user)
set_language_if_valid user.language
recipients user.mail
subject l(:mail_subject_register, Setting.app_title)
body :user => user,
:login_url => url_for(:controller => 'account', :action => 'login')
end
def lost_password(token)
set_language_if_valid(token.user.language)
recipients token.user.mail
@@ -189,12 +204,6 @@ class Mailer < ActionMailer::Base
set_language_if_valid Setting.default_language
from Setting.mail_from
# URL options
h = Setting.host_name
h = h.to_s.gsub(%r{\/.*$}, '') unless ActionController::AbstractRequest.relative_url_root.blank?
default_url_options[:host] = h
default_url_options[:protocol] = Setting.protocol
# Common headers
headers 'X-Mailer' => 'Redmine',
'X-Redmine-Host' => Setting.host_name,

View File

@@ -3,7 +3,7 @@
<tbody>
<% line_num = 1 %>
<% syntax_highlight(filename, to_utf8(content)).each_line do |line| %>
<tr><th class="line-num" id="L<%= line_num %>"><%= line_num %></th><td class="line-code"><pre><%= line %></pre></td></tr>
<tr><th class="line-num" id="L<%= line_num %>"><a href="#L<%= line_num %>"><%= line_num %></a></th><td class="line-code"><pre><%= line %></pre></td></tr>
<% line_num += 1 %>
<% end %>
</tbody>

View File

@@ -42,6 +42,7 @@
<% else %>
<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
<p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
<% end %>
<p class="other-formats">
<%= l(:label_export_to) %>
@@ -50,7 +51,6 @@
<span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
</p>
<% end %>
<% end %>
<% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %>

View File

@@ -47,18 +47,20 @@
<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
<div id="sidebar">
<%= yield :sidebar %>
<%= call_hook :view_layouts_base_sidebar %>
</div>
<div id="content">
<%= render_flash_messages %>
<%= yield %>
<%= call_hook :view_layouts_base_content %>
</div>
</div>
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
<div id="footer">
Powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %> &copy; 2006-2008 Jean-Philippe Lang
Powered by <%= link_to Redmine::Info.app_name, Redmine::Info.url %> &copy; 2006-2009 Jean-Philippe Lang
</div>
</div>
<%= call_hook :view_layouts_base_body_bottom %>

View File

@@ -0,0 +1,2 @@
<p><%= l(:notice_account_activated) %></p>
<p><%= l(:label_login) %>: <%= link_to @login_url, @login_url %></p>

View File

@@ -0,0 +1,2 @@
<%= l(:notice_account_activated) %>
<%= l(:label_login) %>: <%= @login_url %>

View File

@@ -46,7 +46,9 @@
<% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3>
<p><% @activity.event_types.each do |t| %>
<label><%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> <%= l("label_#{t.singularize}_plural")%></label><br />
<%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %>
<%= link_to(l("label_#{t.singularize}_plural"), {"show_#{t}" => 1, :user_id => params[:user_id]})%>
<br />
<% end %></p>
<% if @project && @project.active_children.any? %>
<p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>

View File

@@ -6,7 +6,7 @@
<% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
<table class="list">
<table class="list files">
<thead><tr>
<%= sort_header_tag('filename', :caption => l(:field_filename)) %>
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
@@ -19,15 +19,19 @@
<% @containers.each do |container| %>
<% next if container.attachments.empty? -%>
<% if container.is_a?(Version) -%>
<tr><th colspan="6" align="left"><span class="icon icon-package"><b><%=h container %></b></span></th></tr>
<tr>
<th colspan="6" align="left">
<%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
</th>
</tr>
<% end -%>
<% container.attachments.each do |file| %>
<tr class="<%= cycle("odd", "even") %>">
<td><%= link_to_attachment file, :download => true, :title => file.description %></td>
<td align="center"><%= format_time(file.created_on) %></td>
<td align="center"><%= number_to_human_size(file.filesize) %></td>
<td align="center"><%= file.downloads %></td>
<td align="center"><small><%= file.digest %></small></td>
<tr class="file <%= cycle("odd", "even") %>">
<td class="filename"><%= link_to_attachment file, :download => true, :title => file.description %></td>
<td class="created_on"><%= format_time(file.created_on) %></td>
<td class="filesize"><%= number_to_human_size(file.filesize) %></td>
<td class="downloads"><%= file.downloads %></td>
<td class="digest"><%= file.digest %></td>
<td align="center">
<%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file},
:confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %>

View File

@@ -11,7 +11,7 @@
<% syntax_highlight(@path, to_utf8(@annotate.content)).each_line do |line| %>
<% revision = @annotate.revisions[line_num-1] %>
<tr class="bloc-<%= revision.nil? ? 0 : colors[revision.identifier || revision.revision] %>">
<th class="line-num"><%= line_num %></th>
<th class="line-num" id="L<%= line_num %>"><a href="#L<%= line_num %>"><%= line_num %></a></th>
<td class="revision">
<%= (revision.identifier ? link_to(format_revision(revision.identifier), :action => 'revision', :id => @project, :rev => revision.identifier) : format_revision(revision.revision)) if revision %></td>
<td class="author"><%= h(revision.author.to_s.split('<').first) if revision %></td>

View File

@@ -11,12 +11,12 @@
<%= text_field_tag 'settings[issues_export_limit]', Setting.issues_export_limit, :size => 6 %></p>
</div>
<fieldset class="box"><legend><%= l(:setting_issue_list_default_columns) %></legend>
<fieldset class="box settings"><legend><%= l(:setting_issue_list_default_columns) %></legend>
<%= hidden_field_tag 'settings[issue_list_default_columns][]', '' %>
<p><% Query.new.available_columns.each do |column| %>
<% Query.new.available_columns.each do |column| %>
<label><%= check_box_tag 'settings[issue_list_default_columns][]', column.name, Setting.issue_list_default_columns.include?(column.name.to_s) %>
<%= column.caption %></label>
<% end %></p>
<%= column.caption %></label><br />
<% end %>
</fieldset>
<%= submit_tag l(:button_save) %>

View File

@@ -5,6 +5,24 @@ Copyright (C) 2006-2009 Jean-Philippe Lang
http://www.redmine.org/
== 2009-03-07 v0.8.2
* Send an email to the user when an administrator activates a registered user
* Strip keywords from received email body
* Footer updated to 2009
* Show RSS-link even when no issues is found
* One click filter action in activity view
* Clickable/linkable line #'s while browsing the repo or viewing a file
* Links to versions on files list
* Added request and controller objects to the hooks by default
* Fixed: exporting an issue with attachments to PDF raises an error
* Fixed: "too few arguments" error may occur on activerecord error translation
* Fixed: "Default columns Displayed on the Issues list" setting is not easy to read
* Fixed: visited links to closed tickets are not striked through with IE6
* Fixed: MailHandler#plain_text_body returns nil if there was nothing to strip
* Fixed: MailHandler raises an error when processing an email without From header
== 2009-02-15 v0.8.1
* Select watchers on new issue form

View File

@@ -21,6 +21,8 @@ require 'rfpdf/chinese'
module Redmine
module Export
module PDF
include ActionView::Helpers::NumberHelper
class IFPDF < FPDF
include GLoc
attr_accessor :footer_date

View File

@@ -17,6 +17,8 @@
module Redmine
module Hook
include ActionController::UrlWriter
@@listener_classes = []
@@listeners = nil
@@hook_listeners = {}
@@ -55,11 +57,12 @@ module Redmine
# Calls a hook.
# Returns the listeners response.
def call_hook(hook, context={})
response = ''
hook_listeners(hook).each do |listener|
response << listener.send(hook, context).to_s
returning [] do |response|
hls = hook_listeners(hook)
if hls.any?
hls.each {|listener| response << listener.send(hook, context)}
end
end
response
end
end
@@ -73,8 +76,9 @@ module Redmine
Redmine::Hook.add_listener(child)
super
end
end
# Listener class used for views hooks.
# Listeners that inherit this class will include various helpers by default.
class ViewListener < Listener
@@ -91,17 +95,54 @@ module Redmine
include ActionView::Helpers::TextHelper
include ActionController::UrlWriter
include ApplicationHelper
# Default to creating links using only the path. Subclasses can
# change this default as needed
def self.default_url_options
{:only_path => true }
end
# Helper method to directly render a partial using the context:
#
# class MyHook < Redmine::Hook::ViewListener
# render_on :view_issues_show_details_bottom, :partial => "show_more_data"
# end
#
def self.render_on(hook, options={})
define_method hook do |context|
context[:controller].send(:render_to_string, {:locals => context}.merge(options))
end
end
end
# Helper module included in ApplicationHelper so that hooks can be called
# in views like this:
# Helper module included in ApplicationHelper and ActionControllerso that
# hooks can be called in views like this:
#
# <%= call_hook(:some_hook) %>
# <%= call_hook(:another_hook, :foo => 'bar' %>
#
# Current project is automatically added to the call context.
# Or in controllers like:
# call_hook(:some_hook)
# call_hook(:another_hook, :foo => 'bar'
#
# Hooks added to views will be concatenated into a string. Hooks added to
# controllers will return an array of results.
#
# Several objects are automatically added to the call context:
#
# * project => current project
# * request => Request instance
# * controller => current Controller instance
#
module Helper
def call_hook(hook, context={})
Redmine::Hook.call_hook(hook, {:project => @project}.merge(context))
if is_a?(ActionController::Base)
default_context = {:controller => self, :project => @project, :request => request}
Redmine::Hook.call_hook(hook, default_context.merge(context))
else
default_context = {:controller => controller, :project => @project, :request => request}
Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ')
end
end
end
end

38
lib/redmine/utils.rb Normal file
View File

@@ -0,0 +1,38 @@
# Redmine - project management software
# Copyright (C) 2006-2009 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module Redmine
module Utils
class << self
# Returns the relative root url of the application
def relative_url_root
ActionController::Base.respond_to?('relative_url_root') ?
ActionController::Base.relative_url_root.to_s :
ActionController::AbstractRequest.relative_url_root.to_s
end
# Sets the relative root url of the application
def relative_url_root=(arg)
if ActionController::Base.respond_to?('relative_url_root=')
ActionController::Base.relative_url_root=arg
else
ActionController::AbstractRequest.relative_url_root=arg
end
end
end
end
end

View File

@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc:
MAJOR = 0
MINOR = 8
TINY = 1
TINY = 2
# Branch values:
# * official release: nil

View File

@@ -18,7 +18,7 @@ h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; bord
padding: 0px 0px 0px 0px;
white-space:nowrap;
}
#top-menu a {color: #fff; padding-right: 8px; font-weight: bold;}
#top-menu a {color: #fff; margin-right: 8px; font-weight: bold;}
#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; }
#account {float:right;}
@@ -76,7 +76,7 @@ a, a:link, a:visited{ color: #2A5685; text-decoration: none; }
a:hover, a:active{ color: #c61a1a; text-decoration: underline;}
a img{ border: 0; }
a.issue.closed { text-decoration: line-through; }
a.issue.closed, a.issue.closed:link, a.issue.closed:visited { text-decoration: line-through; }
/***** Tables *****/
table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; }
@@ -104,6 +104,10 @@ tr.entry.file td.filename a { margin-left: 16px; }
tr.changeset td.author { text-align: center; width: 15%; }
tr.changeset td.committed_on { text-align: center; width: 15%; }
tr.file td { text-align: center; }
tr.file td.filename { text-align: left; padding-left: 24px; }
tr.file td.digest { font-size: 80%; }
tr.message { height: 2.6em; }
tr.message td.last_message { font-size: 80%; }
tr.message.locked td.subject a { background-image: url(../images/locked.png); }

View File

@@ -40,6 +40,10 @@ table.filecontent th.line-num {
padding-right: 3px;
color: #999;
}
table.filecontent th.line-num a {
text-decoration: none;
color: inherit;
}
table.filecontent td.line-code pre {
white-space: pre-wrap; /* CSS2.1 compliant */
white-space: -moz-pre-wrap; /* Mozilla-based browsers */

View File

@@ -0,0 +1,40 @@
Received: from osiris ([127.0.0.1])
by OSIRIS
with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200
Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris>
To: <redmine@somenet.foo>
Subject: New ticket on a given project
Date: Sun, 22 Jun 2008 12:28:07 +0200
MIME-Version: 1.0
Content-Type: text/plain;
format=flowed;
charset="iso-8859-1";
reply-type=original
Content-Transfer-Encoding: 7bit
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2900.2869
X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869
Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet
turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus
blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti
sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In
in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras
sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum
id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus
eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique
sed, mauris. Pellentesque habitant morbi tristique senectus et netus et
malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse
platea dictumst.
Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque
sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem.
Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et,
dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed,
massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo
pulvinar dui, a gravida orci mi eget odio. Nunc a lacus.
Project: onlinestore
Status: Resolved

View File

@@ -253,7 +253,7 @@ class IssuesControllerTest < Test::Unit::TestCase
end
def test_show_export_to_pdf
get :show, :id => 1, :format => 'pdf'
get :show, :id => 3, :format => 'pdf'
assert_response :success
assert_equal 'application/pdf', @response.content_type
assert @response.body.starts_with?('%PDF')

View File

@@ -64,6 +64,22 @@ class UsersControllerTest < Test::Unit::TestCase
assert_equal 2, Member.find(1).role_id
end
def test_edit_with_activation_should_send_a_notification
u = User.new(:firstname => 'Foo', :lastname => 'Bar', :mail => 'foo.bar@somenet.foo', :language => 'fr')
u.login = 'foo'
u.status = User::STATUS_REGISTERED
u.save!
ActionMailer::Base.deliveries.clear
Setting.bcc_recipients = '1'
post :edit, :id => u.id, :user => {:status => User::STATUS_ACTIVE}
assert u.reload.active?
mail = ActionMailer::Base.deliveries.last
assert_not_nil mail
assert_equal ['foo.bar@somenet.foo'], mail.bcc
assert mail.body.include?(ll('fr', :notice_account_activated))
end
def test_destroy_membership
post :destroy_membership, :id => 2, :membership_id => 1
assert_redirected_to 'users/edit/2'

View File

@@ -19,8 +19,10 @@ require File.dirname(__FILE__) + '/../../../test_helper'
class Redmine::Hook::ManagerTest < Test::Unit::TestCase
fixtures :issues
# Some hooks that are manually registered in these tests
class TestHook < Redmine::Hook::Listener; end
class TestHook < Redmine::Hook::ViewListener; end
class TestHook1 < TestHook
def view_layouts_base_html_head(context)
@@ -39,10 +41,27 @@ class Redmine::Hook::ManagerTest < Test::Unit::TestCase
"Context keys: #{context.keys.collect(&:to_s).sort.join(', ')}."
end
end
class TestLinkToHook < TestHook
def view_layouts_base_html_head(context)
link_to('Issues', :controller => 'issues')
end
end
class TestHookHelperController < ActionController::Base
include Redmine::Hook::Helper
end
class TestHookHelperView < ActionView::Base
include Redmine::Hook::Helper
end
Redmine::Hook.clear_listeners
def setup
@hook_module = Redmine::Hook
@hook_helper = TestHookHelperController.new
@view_hook_helper = TestHookHelperView.new(RAILS_ROOT + '/app/views')
end
def teardown
@@ -67,17 +86,81 @@ class Redmine::Hook::ManagerTest < Test::Unit::TestCase
def test_call_hook
@hook_module.add_listener(TestHook1)
assert_equal 'Test hook 1 listener.', @hook_module.call_hook(:view_layouts_base_html_head)
assert_equal ['Test hook 1 listener.'], @hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_with_context
@hook_module.add_listener(TestHook3)
assert_equal 'Context keys: bar, foo.', @hook_module.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
assert_equal ['Context keys: bar, controller, foo, project, request.'],
@hook_helper.call_hook(:view_layouts_base_html_head, :foo => 1, :bar => 'a')
end
def test_call_hook_with_multiple_listeners
@hook_module.add_listener(TestHook1)
@hook_module.add_listener(TestHook2)
assert_equal 'Test hook 1 listener.Test hook 2 listener.', @hook_module.call_hook(:view_layouts_base_html_head)
assert_equal ['Test hook 1 listener.', 'Test hook 2 listener.'], @hook_helper.call_hook(:view_layouts_base_html_head)
end
# Context: Redmine::Hook::Helper.call_hook default_url
def test_call_hook_default_url_options
@hook_module.add_listener(TestLinkToHook)
assert_equal ['<a href="/issues">Issues</a>'], @hook_helper.call_hook(:view_layouts_base_html_head)
end
# Context: Redmine::Hook::Helper.call_hook
def test_call_hook_with_project_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /project/i, @hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_controller_with_controller_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /controller/i, @hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_controller_with_request_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /request/i, @hook_helper.call_hook(:view_layouts_base_html_head)[0]
end
def test_call_hook_from_view_with_project_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /project/i, @view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_with_controller_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /controller/i, @view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_with_request_added_to_context
@hook_module.add_listener(TestHook3)
assert_match /request/i, @view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_from_view_should_join_responses_with_a_space
@hook_module.add_listener(TestHook1)
@hook_module.add_listener(TestHook2)
assert_equal 'Test hook 1 listener. Test hook 2 listener.',
@view_hook_helper.call_hook(:view_layouts_base_html_head)
end
def test_call_hook_should_not_change_the_default_url_for_email_notifications
issue = Issue.find(1)
ActionMailer::Base.deliveries.clear
Mailer.deliver_issue_add(issue)
mail = ActionMailer::Base.deliveries.last
@hook_module.add_listener(TestLinkToHook)
@hook_helper.call_hook(:view_layouts_base_html_head)
ActionMailer::Base.deliveries.clear
Mailer.deliver_issue_add(issue)
mail2 = ActionMailer::Base.deliveries.last
assert_equal mail.body, mail2.body
end
end

View File

@@ -47,7 +47,11 @@ class MailHandlerTest < Test::Unit::TestCase
assert_equal 'New ticket on a given project', issue.subject
assert_equal User.find_by_login('jsmith'), issue.author
assert_equal Project.find(2), issue.project
assert_equal IssueStatus.find_by_name('Resolved'), issue.status
assert issue.description.include?('Lorem ipsum dolor sit amet, consectetuer adipiscing elit.')
# keywords should be removed from the email body
assert !issue.description.match(/^Project:/i)
assert !issue.description.match(/^Status:/i)
end
def test_add_issue_with_status
@@ -111,6 +115,7 @@ class MailHandlerTest < Test::Unit::TestCase
issue.reload
assert_equal 'New ticket with custom field values', issue.subject
assert_equal 'Value for a custom field', issue.custom_value_for(CustomField.find_by_name('Searchable field')).value
assert !issue.description.match(/^searchable field:/i)
end
def test_add_issue_with_cc
@@ -122,6 +127,11 @@ class MailHandlerTest < Test::Unit::TestCase
assert_equal 1, issue.watchers.size
end
def test_add_issue_without_from_header
Role.anonymous.add_permission!(:add_issues)
assert_equal false, submit_email('ticket_without_from_header.eml')
end
def test_add_issue_note
journal = submit_email('ticket_reply.eml')
assert journal.is_a?(Journal)

View File

@@ -67,6 +67,7 @@ class RepositoryTest < Test::Unit::TestCase
def test_scan_changesets_for_issue_ids
Setting.default_language = 'en'
set_language_if_valid('en')
# choosing a status to apply to fix issues
Setting.commit_fix_status_id = IssueStatus.find(:first, :conditions => ["is_closed = ?", true]).id