Compare commits

...
57 Commits
Author SHA1 Message Date
Jean-Philippe Lang 0bdef7d797 tagged version 0.8.5
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/tags/0.8.5@2886 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 12:39:40 +00:00
Jean-Philippe Lang d884cc3870 CHANGELOG update
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2885 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 12:01:35 +00:00
Jean-Philippe Lang bdfee87349 Merged r2766 and r2783 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2884 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 11:58:48 +00:00
Jean-Philippe Lang 2ec385858f Merged r2722, r2771, r2772 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2883 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 11:53:27 +00:00
Jean-Philippe Lang 94488269d1 Merged r2768, r2773, r2774, r2775, r2796 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2882 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 11:46:39 +00:00
Jean-Philippe Lang 3d0fbea9fd Merged r2797, r2804, r2814, r2820, r2837, r2838 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2881 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-09-13 11:36:09 +00:00
Eric Davis 3d68b60063 Fixed a merge error in r2830, wrong hook variables where used.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2831 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-08-01 18:28:57 +00:00
Eric Davis 27b110a61b Merged r2829 from trunk
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2830 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-08-01 18:17:46 +00:00
Jean-Philippe Lang d6394b60a5 Merged r2794 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2795 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-06-28 11:57:04 +00:00
Eric Davis ffd720eec9 Merged r2790 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2791 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-06-14 16:23:56 +00:00
Jean-Philippe Lang 50c0cebe96 Merged r2763 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2764 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-25 18:14:15 +00:00
Jean-Philippe Lang 1342228771 Translations updates.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2753 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-17 14:05:55 +00:00
Jean-Philippe Lang 6872c5e0b9 Updates for 0.8.4 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2748 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-17 09:16:23 +00:00
Jean-Philippe Lang e27460a0a7 Backported r2740 to r2742 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2747 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-17 09:13:38 +00:00
Jean-Philippe Lang 3f6656a495 Merged r2697, r2720, r2723, r2724, r2727, r2745 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2746 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-17 08:57:38 +00:00
Jean-Philippe Lang a3f69e248a Merged r2718 from trunk (#3291).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2719 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-10 08:40:51 +00:00
Eric Davis 3022d067ba Merged r2713 from trunk. #3086
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2714 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-06 04:57:52 +00:00
Jean-Philippe Lang e06987ab52 Merged r2707 and r2708 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2709 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-04 17:39:57 +00:00
Jean-Philippe Lang ace65df230 Merged r2705 from trunk (#3291).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2706 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-05-04 16:50:03 +00:00
Jean-Philippe Lang c5dadfd322 Backported r2690 from trunk (#3229).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2691 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-25 09:09:50 +00:00
Eric Davis 7a59f2df12 Merged r2686, r2687 from trunk
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2688 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-24 21:30:05 +00:00
Jean-Philippe Lang 7b699af837 Merged r2664, r2665, r2670, r2674, r2677, r2679 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2681 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-24 16:13:35 +00:00
Jean-Philippe Lang babbe88a86 Updates for 0.8.3 release.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2657 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:45:51 +00:00
Jean-Philippe Lang 51a9f6a6eb Merged r2655 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2656 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:35:34 +00:00
Jean-Philippe Lang 16810acf01 Merged r2610, r2611 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2654 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:16:34 +00:00
Jean-Philippe Lang e28b5e1f08 Merged r2643 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2653 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:09:59 +00:00
Jean-Philippe Lang aa38f755c6 Backported r2609 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2652 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:07:55 +00:00
Jean-Philippe Lang 2679cc2045 Merged r2574, r2578, r2589, r2615, r2641, r2645, r2646 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2651 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 12:03:03 +00:00
Jean-Philippe Lang b6600d5fe9 Merged r2563, r2566, r2567, r2568, r2569, r2582 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2650 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-04-05 11:52:49 +00:00
Jean-Philippe Lang 37da5ba187 Backported r2573, r2591 and r2592 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2593 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-03-15 10:10:39 +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
Jean-Philippe Lang 3d1bd79ffb Set version to 0.8.1
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2470 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-15 09:08:26 +00:00
Jean-Philippe Lang 7f957653ad Merged r2463, r2465, r2467, r2468 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2469 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-15 09:04:24 +00:00
Jean-Philippe Lang 9a9141041e Merged r2461 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2462 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-13 17:32:27 +00:00
Jean-Philippe Lang bc4249e3d3 Merged r2270, r2344, r2359, r2360, r2362, r2363, r2415, r2423, r2424 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2425 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-02-09 18:46:00 +00:00
Jean-Philippe Lang fae04f3ae1 Merged r2246 and r2248 from trunk (#2456).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2310 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-24 13:01:31 +00:00
Jean-Philippe Lang b13ef64794 Merged r2265 from trunk (#2523).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2309 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-24 12:27:56 +00:00
Jean-Philippe Lang 683e1c5d73 Merged r2266 from trunk (#2522).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2308 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-24 12:13:16 +00:00
Jean-Philippe Lang 1c1755d278 Merged r2280 from trunk (#2506).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2307 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-24 12:11:52 +00:00
Jean-Philippe Lang 5e6ff86f47 Merged r2302 from trunk (#2466).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2306 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-24 12:10:24 +00:00
Jean-Philippe Lang 764393aa6a Merged r2250 and r2251 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2252 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-10 10:51:59 +00:00
Jean-Philippe Lang 3155b8ccad Merged r2226 and r2233 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2245 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-05 18:16:14 +00:00
Jean-Philippe Lang 567c8ed9b0 Fixed: Darcs adapter works on Win32 only (wrong quotes in commands #2402).
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2231 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-04 13:24:56 +00:00
Jean-Philippe Lang 49b6f9e4dd Merged r2218 to r2225 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2230 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-04 13:10:16 +00:00
Jean-Philippe Lang c9d4d3a2be Merged r2209 to r2211 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2229 e93f8b46-1217-0410-a6f0-8f06a7374b81
2009-01-04 13:03:34 +00:00
Jean-Philippe Lang 31178553f3 Merged r2116, r2117 and r2187 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2217 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-12-31 11:40:03 +00:00
Jean-Philippe Lang dea10c54f9 Merged r2164 to r2167, r2188 and r2189 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2216 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-12-31 11:31:02 +00:00
Jean-Philippe Lang 6abd32be9e Merged r2212 to r2214 from trunk.
git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/0.8-stable@2215 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-12-31 10:47:19 +00:00
179 changed files with 2118 additions and 932 deletions
+1
View File
@@ -63,6 +63,7 @@ class AccountController < ApplicationController
token = Token.create(:user => user, :action => 'autologin') token = Token.create(:user => user, :action => 'autologin')
cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now } cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
end end
call_hook(:controller_account_success_authentication_after, {:user => user })
redirect_back_or_default :controller => 'my', :action => 'page' redirect_back_or_default :controller => 'my', :action => 'page'
end end
end end
+1
View File
@@ -86,6 +86,7 @@ class AdminController < ApplicationController
@flags = { @flags = {
:default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?, :default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?,
:file_repository_writable => File.writable?(Attachment.storage_path), :file_repository_writable => File.writable?(Attachment.storage_path),
:plugin_assets_writable => File.writable?(Engines.public_directory),
:rmagick_available => Object.const_defined?(:Magick) :rmagick_available => Object.const_defined?(:Magick)
} }
end end
+5 -1
View File
@@ -175,6 +175,7 @@ class ApplicationController < ActionController::Base
# TODO: move to model # TODO: move to model
def attach_files(obj, attachments) def attach_files(obj, attachments)
attached = [] attached = []
unsaved = []
if attachments && attachments.is_a?(Hash) if attachments && attachments.is_a?(Hash)
attachments.each_value do |attachment| attachments.each_value do |attachment|
file = attachment['file'] file = attachment['file']
@@ -183,7 +184,10 @@ class ApplicationController < ActionController::Base
:file => file, :file => file,
:description => attachment['description'].to_s.strip, :description => attachment['description'].to_s.strip,
:author => User.current) :author => User.current)
attached << a unless a.new_record? a.new_record? ? (unsaved << a) : (attached << a)
end
if unsaved.any?
flash[:warning] = l(:warning_attachments_not_saved, unsaved.size)
end end
end end
attached attached
+28 -9
View File
@@ -1,5 +1,5 @@
# redMine - project management software # Redmine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2008 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -17,7 +17,11 @@
class AttachmentsController < ApplicationController class AttachmentsController < ApplicationController
before_filter :find_project before_filter :find_project
before_filter :read_authorize, :except => :destroy
before_filter :delete_authorize, :only => :destroy
verify :method => :post, :only => :destroy
def show def show
if @attachment.is_diff? if @attachment.is_diff?
@diff = File.new(@attachment.diskfile, "rb").read @diff = File.new(@attachment.diskfile, "rb").read
@@ -31,25 +35,40 @@ class AttachmentsController < ApplicationController
end end
def download def download
@attachment.increment_download if @attachment.container.is_a?(Version) if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project)
@attachment.increment_download
end
# images are sent inline # images are sent inline
send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename),
:type => @attachment.content_type, :type => @attachment.content_type,
:disposition => (@attachment.image? ? 'inline' : 'attachment') :disposition => (@attachment.image? ? 'inline' : 'attachment')
end end
def destroy
# Make sure association callbacks are called
@attachment.container.attachments.delete(@attachment)
redirect_to :back
rescue ::ActionController::RedirectBackError
redirect_to :controller => 'projects', :action => 'show', :id => @project
end
private private
def find_project def find_project
@attachment = Attachment.find(params[:id]) @attachment = Attachment.find(params[:id])
# Show 404 if the filename in the url is wrong # Show 404 if the filename in the url is wrong
raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename
@project = @attachment.project @project = @attachment.project
permission = @attachment.container.is_a?(Version) ? :view_files : "view_#{@attachment.container.class.name.underscore.pluralize}".to_sym
allowed = User.current.allowed_to?(permission, @project)
allowed ? true : (User.current.logged? ? render_403 : require_login)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
def read_authorize
@attachment.visible? ? true : deny_access
end
def delete_authorize
@attachment.deletable? ? true : deny_access
end
end end
@@ -46,6 +46,7 @@ class CustomFieldsController < ApplicationController
end end
if request.post? and @custom_field.save if request.post? and @custom_field.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
redirect_to :action => 'list', :tab => @custom_field.class.name redirect_to :action => 'list', :tab => @custom_field.class.name
end end
@trackers = Tracker.find(:all, :order => 'position') @trackers = Tracker.find(:all, :order => 'position')
@@ -58,6 +59,7 @@ class CustomFieldsController < ApplicationController
@custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : [] @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : []
end end
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
redirect_to :action => 'list', :tab => @custom_field.class.name redirect_to :action => 'list', :tab => @custom_field.class.name
end end
@trackers = Tracker.find(:all, :order => 'position') @trackers = Tracker.find(:all, :order => 'position')
-5
View File
@@ -71,11 +71,6 @@ class DocumentsController < ApplicationController
Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added') Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added')
redirect_to :action => 'show', :id => @document redirect_to :action => 'show', :id => @document
end end
def destroy_attachment
@document.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'show', :id => @document
end
private private
def find_project def find_project
+16 -22
View File
@@ -18,20 +18,18 @@
class IssuesController < ApplicationController class IssuesController < ApplicationController
menu_item :new_issue, :only => :new menu_item :new_issue, :only => :new
before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment] before_filter :find_issue, :only => [:show, :edit, :reply]
before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy]
before_filter :find_project, :only => [:new, :update_form, :preview] before_filter :find_project, :only => [:new, :update_form, :preview]
before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu] before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu]
before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar] before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar]
accept_key_auth :index, :changes accept_key_auth :index, :show, :changes
helper :journals helper :journals
helper :projects helper :projects
include ProjectsHelper include ProjectsHelper
helper :custom_fields helper :custom_fields
include CustomFieldsHelper include CustomFieldsHelper
helper :ifpdf
include IfpdfHelper
helper :issue_relations helper :issue_relations
include IssueRelationsHelper include IssueRelationsHelper
helper :watchers helper :watchers
@@ -43,6 +41,7 @@ class IssuesController < ApplicationController
include SortHelper include SortHelper
include IssuesHelper include IssuesHelper
helper :timelog helper :timelog
include Redmine::Export::PDF
def index def index
retrieve_query retrieve_query
@@ -68,7 +67,7 @@ class IssuesController < ApplicationController
format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? } format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? }
format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") }
format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') } format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') }
format.pdf { send_data(render(:template => 'issues/index.rfpdf', :layout => false), :type => 'application/pdf', :filename => 'export.pdf') } format.pdf { send_data(issues_to_pdf(@issues, @project), :type => 'application/pdf', :filename => 'export.pdf') }
end end
else else
# Send html if the query is not valid # Send html if the query is not valid
@@ -106,7 +105,7 @@ class IssuesController < ApplicationController
respond_to do |format| respond_to do |format|
format.html { render :template => 'issues/show.rhtml' } format.html { render :template => 'issues/show.rhtml' }
format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' } format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' }
format.pdf { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") }
end end
end end
@@ -123,7 +122,10 @@ class IssuesController < ApplicationController
render :nothing => true, :layout => true render :nothing => true, :layout => true
return return
end end
@issue.attributes = params[:issue] if params[:issue].is_a?(Hash)
@issue.attributes = params[:issue]
@issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project)
end
@issue.author = User.current @issue.author = User.current
default_status = IssueStatus.default default_status = IssueStatus.default
@@ -145,7 +147,8 @@ class IssuesController < ApplicationController
attach_files(@issue, params[:attachments]) attach_files(@issue, params[:attachments])
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added')
redirect_to :controller => 'issues', :action => 'show', :id => @issue redirect_to(params[:continue] ? { :action => 'new', :tracker_id => @issue.tracker } :
{ :action => 'show', :id => @issue })
return return
end end
end end
@@ -183,7 +186,7 @@ class IssuesController < ApplicationController
if (@time_entry.hours.nil? || @time_entry.valid?) && @issue.save if (@time_entry.hours.nil? || @time_entry.valid?) && @issue.save
# Log spend time # Log spend time
if current_role.allowed_to?(:log_time) if User.current.allowed_to?(:log_time, @project)
@time_entry.save @time_entry.save
end end
if !journal.new_record? if !journal.new_record?
@@ -315,17 +318,6 @@ class IssuesController < ApplicationController
@issues.each(&:destroy) @issues.each(&:destroy)
redirect_to :action => 'index', :project_id => @project redirect_to :action => 'index', :project_id => @project
end end
def destroy_attachment
a = @issue.attachments.find(params[:attachment_id])
a.destroy
journal = @issue.init_journal(User.current)
journal.details << JournalDetail.new(:property => 'attachment',
:prop_key => a.id,
:old_value => a.filename)
journal.save
redirect_to :action => 'show', :id => @issue
end
def gantt def gantt
@gantt = Redmine::Helpers::Gantt.new(params) @gantt = Redmine::Helpers::Gantt.new(params)
@@ -351,10 +343,12 @@ class IssuesController < ApplicationController
@gantt.events = events @gantt.events = events
end end
basename = (@project ? "#{@project.identifier}-" : '') + 'gantt'
respond_to do |format| respond_to do |format|
format.html { render :template => "issues/gantt.rhtml", :layout => !request.xhr? } format.html { render :template => "issues/gantt.rhtml", :layout => !request.xhr? }
format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{@project.identifier}-gantt.png") } if @gantt.respond_to?('to_image') format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image')
format.pdf { send_data(render(:template => "issues/gantt.rfpdf", :layout => false), :type => 'application/pdf', :filename => "#{@project.nil? ? '' : "#{@project.identifier}-" }gantt.pdf") } format.pdf { send_data(gantt_to_pdf(@gantt, @project), :type => 'application/pdf', :filename => "#{basename}.pdf") }
end end
end end
+2
View File
@@ -46,6 +46,7 @@ class MessagesController < ApplicationController
@message.sticky = params[:message]['sticky'] @message.sticky = params[:message]['sticky']
end end
if request.post? && @message.save if request.post? && @message.save
call_hook(:controller_messages_new_after_save, { :params => params, :message => @message})
attach_files(@message, params[:attachments]) attach_files(@message, params[:attachments])
redirect_to :action => 'show', :id => @message redirect_to :action => 'show', :id => @message
end end
@@ -58,6 +59,7 @@ class MessagesController < ApplicationController
@reply.board = @board @reply.board = @board
@topic.children << @reply @topic.children << @reply
if !@reply.new_record? if !@reply.new_record?
call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply})
attach_files(@reply, params[:attachments]) attach_files(@reply, params[:attachments])
end end
redirect_to :action => 'show', :id => @topic redirect_to :action => 'show', :id => @topic
+1
View File
@@ -65,6 +65,7 @@ class NewsController < ApplicationController
flash[:notice] = l(:label_comment_added) flash[:notice] = l(:label_comment_added)
redirect_to :action => 'show', :id => @news redirect_to :action => 'show', :id => @news
else else
show
render :action => 'show' render :action => 'show'
end end
end end
+13 -6
View File
@@ -33,8 +33,6 @@ class ProjectsController < ApplicationController
include SortHelper include SortHelper
helper :custom_fields helper :custom_fields
include CustomFieldsHelper include CustomFieldsHelper
helper :ifpdf
include IfpdfHelper
helper :issues helper :issues
helper IssuesHelper helper IssuesHelper
helper :queries helper :queries
@@ -84,6 +82,11 @@ class ProjectsController < ApplicationController
# Show @project # Show @project
def show def show
if params[:jump]
# try to redirect to the requested menu item
redirect_to_project_menu_item(@project, params[:jump]) && return
end
@members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role} @members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role}
@subprojects = @project.children.find(:all, :conditions => Project.visible_by(User.current)) @subprojects = @project.children.find(:all, :conditions => Project.visible_by(User.current))
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
@@ -188,10 +191,13 @@ class ProjectsController < ApplicationController
def add_file def add_file
if request.post? if request.post?
@version = @project.versions.find_by_id(params[:version_id]) container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id]))
attachments = attach_files(@version, params[:attachments]) attachments = attach_files(container, params[:attachments])
Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('file_added') if !attachments.empty? && Setting.notified_events.include?('file_added')
Mailer.deliver_attachments_added(attachments)
end
redirect_to :controller => 'projects', :action => 'list_files', :id => @project redirect_to :controller => 'projects', :action => 'list_files', :id => @project
return
end end
@versions = @project.versions.sort @versions = @project.versions.sort
end end
@@ -203,7 +209,8 @@ class ProjectsController < ApplicationController
'size' => "#{Attachment.table_name}.filesize", 'size' => "#{Attachment.table_name}.filesize",
'downloads' => "#{Attachment.table_name}.downloads" 'downloads' => "#{Attachment.table_name}.downloads"
@versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)]
@containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
render :layout => !request.xhr? render :layout => !request.xhr?
end end
@@ -127,6 +127,9 @@ class RepositoriesController < ApplicationController
end end
def annotate def annotate
@entry = @repository.entry(@path, @rev)
show_error_not_found and return unless @entry
@annotate = @repository.scm.annotate(@path, @rev) @annotate = @repository.scm.annotate(@path, @rev)
render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty? render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty?
end end
+1 -1
View File
@@ -40,7 +40,7 @@ class SettingsController < ApplicationController
@options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] } @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] }
@deliveries = ActionMailer::Base.perform_deliveries @deliveries = ActionMailer::Base.perform_deliveries
@guessed_host_and_path = request.host_with_port @guessed_host_and_path = request.host_with_port.dup
@guessed_host_and_path << ('/'+ request.relative_url_root.gsub(%r{^\/}, '')) unless request.relative_url_root.blank? @guessed_host_and_path << ('/'+ request.relative_url_root.gsub(%r{^\/}, '')) unless request.relative_url_root.blank?
end end
+3
View File
@@ -197,6 +197,9 @@ class TimelogController < ApplicationController
render_403 and return if @time_entry && !@time_entry.editable_by?(User.current) render_403 and return if @time_entry && !@time_entry.editable_by?(User.current)
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today) @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry] @time_entry.attributes = params[:time_entry]
call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry })
if request.post? and @time_entry.save if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_back_or_default :action => 'details', :project_id => @time_entry.project redirect_back_or_default :action => 'details', :project_id => @time_entry.project
+5 -1
View File
@@ -75,7 +75,11 @@ class UsersController < ApplicationController
@user.admin = params[:user][:admin] if params[:user][:admin] @user.admin = params[:user][:admin] if params[:user][:admin]
@user.login = params[:user][:login] if params[:user][:login] @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 @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) flash[:notice] = l(:notice_successful_update)
# Give a string to redirect_to otherwise it would use status param as the response code # 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])) redirect_to(url_for(:action => 'list', :status => params[:status], :page => params[:page]))
-6
View File
@@ -37,12 +37,6 @@ class VersionsController < ApplicationController
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end end
def destroy_file
@version.attachments.find(params[:attachment_id]).destroy
flash[:notice] = l(:notice_successful_delete)
redirect_to :controller => 'projects', :action => 'list_files', :id => @project
end
def status_by def status_by
respond_to do |format| respond_to do |format|
format.html { render :action => 'show' } format.html { render :action => 'show' }
+2 -8
View File
@@ -21,7 +21,7 @@ class WikiController < ApplicationController
before_filter :find_wiki, :authorize before_filter :find_wiki, :authorize
before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy] before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy]
verify :method => :post, :only => [:destroy, :destroy_attachment, :protect], :redirect_to => { :action => :index } verify :method => :post, :only => [:destroy, :protect], :redirect_to => { :action => :index }
helper :attachments helper :attachments
include AttachmentsHelper include AttachmentsHelper
@@ -82,6 +82,7 @@ class WikiController < ApplicationController
@content.author = User.current @content.author = User.current
# if page is new @page.save will also save content, but not if page isn't a new record # if page is new @page.save will also save content, but not if page isn't a new record
if (@page.new_record? ? @page.save : @content.save) if (@page.new_record? ? @page.save : @content.save)
call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page})
redirect_to :action => 'index', :id => @project, :page => @page.title redirect_to :action => 'index', :id => @project, :page => @page.title
end end
end end
@@ -181,13 +182,6 @@ class WikiController < ApplicationController
redirect_to :action => 'index', :page => @page.title redirect_to :action => 'index', :page => @page.title
end end
def destroy_attachment
@page = @wiki.find_page(params[:page])
return render_403 unless editable?
@page.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'index', :page => @page.title
end
private private
def find_wiki def find_wiki
+19 -10
View File
@@ -147,6 +147,15 @@ module ApplicationHelper
end end
content content
end end
# Renders flash messages
def render_flash_messages
s = ''
flash.each do |k,v|
s << content_tag('div', v, :class => "flash #{k}")
end
s
end
# Truncates and returns the string as a single line # Truncates and returns the string as a single line
def truncate_single_line(string, *args) def truncate_single_line(string, *args)
@@ -282,16 +291,15 @@ module ApplicationHelper
attachments = attachments.sort_by(&:created_on).reverse attachments = attachments.sort_by(&:created_on).reverse
text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m| text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m|
style = $1 style = $1
filename = $6 filename = $6.downcase
rf = Regexp.new(Regexp.escape(filename), Regexp::IGNORECASE)
# search for the picture in attachments # search for the picture in attachments
if found = attachments.detect { |att| att.filename =~ rf } if found = attachments.detect { |att| att.filename.downcase == filename }
image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1") desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
alt = desc.blank? ? nil : "(#{desc})" alt = desc.blank? ? nil : "(#{desc})"
"!#{style}#{image_url}#{alt}!" "!#{style}#{image_url}#{alt}!"
else else
"!#{style}#{filename}!" m
end end
end end
end end
@@ -377,7 +385,7 @@ module ApplicationHelper
# export:some/file -> Force the download of the file # export:some/file -> Force the download of the file
# Forum messages: # Forum messages:
# message#1218 -> Link to message with id 1218 # message#1218 -> Link to message with id 1218
text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|\s|<|$)}) do |m| text = text.gsub(%r{([\s\(,\-\>]|^)(!)?(attachment|document|version|commit|source|export|message)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|<|$)}) do |m|
leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8 leading, esc, prefix, sep, oid = $1, $2, $3, $5 || $7, $6 || $8
link = nil link = nil
if esc.nil? if esc.nil?
@@ -479,11 +487,11 @@ module ApplicationHelper
full_messages = [] full_messages = []
object.errors.each do |attr, msg| object.errors.each do |attr, msg|
next if msg.nil? next if msg.nil?
msg = msg.first if msg.is_a? Array msg = [msg] unless msg.is_a?(Array)
if attr == "base" if attr == "base"
full_messages << l(msg) full_messages << l(*msg)
else 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
end end
# retrieve custom values error messages # retrieve custom values error messages
@@ -491,8 +499,8 @@ module ApplicationHelper
object.custom_values.each do |v| object.custom_values.each do |v|
v.errors.each do |attr, msg| v.errors.each do |attr, msg|
next if msg.nil? next if msg.nil?
msg = msg.first if msg.is_a? Array msg = [msg] unless msg.is_a?(Array)
full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg) full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(*msg)
end end
end end
end end
@@ -526,6 +534,7 @@ module ApplicationHelper
def back_url_hidden_field_tag def back_url_hidden_field_tag
back_url = params[:back_url] || request.env['HTTP_REFERER'] back_url = params[:back_url] || request.env['HTTP_REFERER']
back_url = CGI.unescape(back_url.to_s)
hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank?
end end
+9 -4
View File
@@ -16,10 +16,15 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module AttachmentsHelper module AttachmentsHelper
# displays the links to a collection of attachments # Displays view/delete links to the attachments of the given object
def link_to_attachments(attachments, options = {}) # Options:
if attachments.any? # :author -- author names are not displayed if set to false
render :partial => 'attachments/links', :locals => {:attachments => attachments, :options => options} def link_to_attachments(container, options = {})
options.assert_valid_keys(:author)
if container.attachments.any?
options = {:deletable => container.attachments_deletable?, :author => true}.merge(options)
render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options}
end end
end end
-85
View File
@@ -1,85 +0,0 @@
# redMine - project management software
# Copyright (C) 2006 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.
require 'iconv'
require 'rfpdf/chinese'
module IfpdfHelper
class IFPDF < FPDF
include GLoc
attr_accessor :footer_date
def initialize(lang)
super()
set_language_if_valid lang
case current_language.to_s
when 'ja'
extend(PDF_Japanese)
AddSJISFont()
@font_for_content = 'SJIS'
@font_for_footer = 'SJIS'
when 'zh'
extend(PDF_Chinese)
AddGBFont()
@font_for_content = 'GB'
@font_for_footer = 'GB'
when 'zh-tw'
extend(PDF_Chinese)
AddBig5Font()
@font_for_content = 'Big5'
@font_for_footer = 'Big5'
else
@font_for_content = 'Arial'
@font_for_footer = 'Helvetica'
end
SetCreator(Redmine::Info.app_name)
SetFont(@font_for_content)
end
def SetFontStyle(style, size)
SetFont(@font_for_content, style, size)
end
def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
@ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
# these quotation marks are not correctly rendered in the pdf
txt = txt.gsub(/[“”]/, '"') if txt
txt = begin
# 0x5c char handling
txtar = txt.split('\\')
txtar << '' if txt[-1] == ?\\
txtar.collect {|x| @ic.iconv(x)}.join('\\').gsub(/\\/, "\\\\\\\\")
rescue
txt
end || ''
super w,h,txt,border,ln,align,fill,link
end
def Footer
SetFont(@font_for_footer, 'I', 8)
SetY(-15)
SetX(15)
Cell(0, 5, @footer_date, 0, 0, 'L')
SetY(-15)
SetX(-30)
Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
end
end
end
+3
View File
@@ -36,7 +36,10 @@ module IssuesHelper
# Returns a string of css classes that apply to the given issue # Returns a string of css classes that apply to the given issue
def css_issue_classes(issue) def css_issue_classes(issue)
s = "issue status-#{issue.status.position} priority-#{issue.priority.position}" s = "issue status-#{issue.status.position} priority-#{issue.priority.position}"
s << ' closed' if issue.closed?
s << ' overdue' if issue.overdue? s << ' overdue' if issue.overdue?
s << ' created-by-me' if User.current.logged? && issue.author_id == User.current.id
s << ' assigned-to-me' if User.current.logged? && issue.assigned_to_id == User.current.id
s s
end end
+7 -1
View File
@@ -40,8 +40,14 @@ module QueriesHelper
else else
case column.name case column.name
when :subject when :subject
h((@project.nil? || @project != issue.project) ? "#{issue.project.name} - " : '') + h((!@project.nil? && @project != issue.project) ? "#{issue.project.name} - " : '') +
link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
when :project
link_to(h(value), :controller => 'projects', :action => 'show', :id => value)
when :assigned_to
link_to(h(value), :controller => 'account', :action => 'show', :id => value)
when :author
link_to(h(value), :controller => 'account', :action => 'show', :id => value)
when :done_ratio when :done_ratio
progress_bar(value, :width => '80px') progress_bar(value, :width => '80px')
when :fixed_version when :fixed_version
+1 -1
View File
@@ -147,7 +147,7 @@ module RepositoriesHelper
def subversion_field_tags(form, repository) def subversion_field_tags(form, repository)
content_tag('p', form.text_field(:url, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + content_tag('p', form.text_field(:url, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) +
'<br />(http://, https://, svn://, file:///)') + '<br />(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') +
content_tag('p', form.text_field(:login, :size => 30)) + content_tag('p', form.text_field(:login, :size => 30)) +
content_tag('p', form.password_field(:password, :size => 30, :name => 'ignore', content_tag('p', form.password_field(:password, :size => 30, :name => 'ignore',
:value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)), :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)),
+8 -2
View File
@@ -16,6 +16,8 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module TimelogHelper module TimelogHelper
include ApplicationHelper
def render_timelog_breadcrumb def render_timelog_breadcrumb
links = [] links = []
links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil})
@@ -33,7 +35,11 @@ module TimelogHelper
end end
def select_hours(data, criteria, value) def select_hours(data, criteria, value)
data.select {|row| row[criteria] == value} if value.to_s.empty?
data.select {|row| row[criteria].blank? }
else
data.select {|row| row[criteria] == value}
end
end end
def sum_hours(data) def sum_hours(data)
@@ -81,7 +87,7 @@ module TimelogHelper
csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
# csv lines # csv lines
entries.each do |entry| entries.each do |entry|
fields = [l_date(entry.spent_on), fields = [format_date(entry.spent_on),
entry.user, entry.user,
entry.activity, entry.activity,
entry.project, entry.project,
+1 -1
View File
@@ -36,7 +36,7 @@ module WikiHelper
words_add += 1 words_add += 1
else else
del_at = pos unless del_at del_at = pos unless del_at
deleted << ' ' + change[2] deleted << ' ' + h(change[2])
words_del += 1 words_del += 1
end end
end end
+18 -11
View File
@@ -33,7 +33,7 @@ class Attachment < ActiveRecord::Base
:author_key => :author_id, :author_key => :author_id,
:find_options => {:select => "#{Attachment.table_name}.*", :find_options => {:select => "#{Attachment.table_name}.*",
:joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " +
"LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id"} "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"}
acts_as_activity_provider :type => 'documents', acts_as_activity_provider :type => 'documents',
:permission => :view_documents, :permission => :view_documents,
@@ -65,14 +65,20 @@ class Attachment < ActiveRecord::Base
nil nil
end end
# Copy temp file to its final location # Copies the temporary file to its final location
# and computes its MD5 hash
def before_save def before_save
if @temp_file && (@temp_file.size > 0) if @temp_file && (@temp_file.size > 0)
logger.debug("saving '#{self.diskfile}'") logger.debug("saving '#{self.diskfile}'")
md5 = Digest::MD5.new
File.open(diskfile, "wb") do |f| File.open(diskfile, "wb") do |f|
f.write(@temp_file.read) buffer = ""
while (buffer = @temp_file.read(8192))
f.write(buffer)
md5.update(buffer)
end
end end
self.digest = self.class.digest(diskfile) self.digest = md5.hexdigest
end end
# Don't save the content type if it's longer than the authorized length # Don't save the content type if it's longer than the authorized length
if self.content_type && self.content_type.length > 255 if self.content_type && self.content_type.length > 255
@@ -98,6 +104,14 @@ class Attachment < ActiveRecord::Base
container.project container.project
end end
def visible?(user=User.current)
container.attachments_visible?(user)
end
def deletable?(user=User.current)
container.attachments_deletable?(user)
end
def image? def image?
self.filename =~ /\.(jpe?g|gif|png)$/i self.filename =~ /\.(jpe?g|gif|png)$/i
end end
@@ -133,11 +147,4 @@ private
end end
df df
end end
# Returns the MD5 digest of the file at given path
def self.digest(filename)
File.open(filename, 'rb') do |f|
Digest::MD5.hexdigest(f.read)
end
end
end end
+2
View File
@@ -112,6 +112,8 @@ class Changeset < ActiveRecord::Base
journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext)) journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext))
issue.status = fix_status issue.status = fix_status
issue.done_ratio = done_ratio if done_ratio issue.done_ratio = done_ratio if done_ratio
Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update,
{ :changeset => self, :issue => issue })
issue.save issue.save
Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated') Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated')
end end
+1 -1
View File
@@ -18,7 +18,7 @@
class Document < ActiveRecord::Base class Document < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
has_many :attachments, :as => :container, :dependent => :destroy acts_as_attachable :delete_permission => :manage_documents
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project
acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"},
+13 -2
View File
@@ -26,13 +26,13 @@ class Issue < ActiveRecord::Base
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
has_many :journals, :as => :journalized, :dependent => :destroy has_many :journals, :as => :journalized, :dependent => :destroy
has_many :attachments, :as => :container, :dependent => :destroy
has_many :time_entries, :dependent => :delete_all has_many :time_entries, :dependent => :delete_all
has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC"
has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all
has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all
acts_as_attachable :after_remove => :attachment_removed
acts_as_customizable acts_as_customizable
acts_as_watchable acts_as_watchable
acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"],
@@ -45,7 +45,7 @@ class Issue < ActiveRecord::Base
acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}, acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]},
:author_key => :author_id :author_key => :author_id
validates_presence_of :subject, :description, :priority, :project, :tracker, :author, :status validates_presence_of :subject, :priority, :project, :tracker, :author, :status
validates_length_of :subject, :maximum => 255 validates_length_of :subject, :maximum => 255
validates_inclusion_of :done_ratio, :in => 0..100 validates_inclusion_of :done_ratio, :in => 0..100
validates_numericality_of :estimated_hours, :allow_nil => true validates_numericality_of :estimated_hours, :allow_nil => true
@@ -266,4 +266,15 @@ class Issue < ActiveRecord::Base
def to_s def to_s
"#{tracker} ##{id}: #{subject}" "#{tracker} ##{id}: #{subject}"
end end
private
# Callback on attachment deletion
def attachment_removed(obj)
journal = init_journal(User.current)
journal.details << JournalDetail.new(:property => 'attachment',
:prop_key => obj.id,
:old_value => obj.filename)
journal.save
end
end end
+1 -1
View File
@@ -38,7 +38,7 @@ class Journal < ActiveRecord::Base
:conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" +
" (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"}
def save def save(*args)
# Do not save an empty journal # Do not save an empty journal
(details.empty? && notes.blank?) ? false : super (details.empty? && notes.blank?) ? false : super
end end
+21 -6
View File
@@ -40,7 +40,7 @@ class MailHandler < ActionMailer::Base
# Processes incoming emails # Processes incoming emails
def receive(email) def receive(email)
@email = 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 unless @user
# Unknown user => the email is ignored # Unknown user => the email is ignored
# TODO: ability to create the user's account # TODO: ability to create the user's account
@@ -90,6 +90,13 @@ class MailHandler < ActionMailer::Base
end end
issue.subject = email.subject.chomp.toutf8 issue.subject = email.subject.chomp.toutf8
issue.description = plain_text_body issue.description = plain_text_body
# custom fields
issue.custom_field_values = issue.available_custom_fields.inject({}) do |h, c|
if value = get_keyword(c.name, :override => true)
h[c.id] = value
end
h
end
issue.save! issue.save!
add_attachments(issue) add_attachments(issue)
logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info
@@ -155,11 +162,18 @@ class MailHandler < ActionMailer::Base
end end
end end
def get_keyword(attr) def get_keyword(attr, options={})
if @@handler_options[:allow_override].include?(attr.to_s) && plain_text_body =~ /^#{attr}:[ \t]*(.+)$/i @keywords ||= {}
$1.strip if @keywords.has_key?(attr)
elsif !@@handler_options[:issue][attr].blank? @keywords[attr]
@@handler_options[:issue][attr] else
@keywords[attr] = begin
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}[ \t]*:[ \t]*(.+)\s*$/i, '')
$1.strip
elsif !@@handler_options[:issue][attr].blank?
@@handler_options[:issue][attr]
end
end
end end
end end
@@ -181,5 +195,6 @@ class MailHandler < ActionMailer::Base
@plain_text_body = plain_text_part.body.to_s @plain_text_body = plain_text_part.body.to_s
end end
@plain_text_body.strip! @plain_text_body.strip!
@plain_text_body
end end
end end
+27 -10
View File
@@ -22,12 +22,19 @@ class Mailer < ActionMailer::Base
include ActionController::UrlWriter 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) def issue_add(issue)
redmine_headers 'Project' => issue.project.identifier, redmine_headers 'Project' => issue.project.identifier,
'Issue-Id' => issue.id, 'Issue-Id' => issue.id,
'Issue-Author' => issue.author.login 'Issue-Author' => issue.author.login
redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
recipients issue.recipients recipients issue.recipients
cc(issue.watcher_recipients - @recipients)
subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}" subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}"
body :issue => issue, body :issue => issue,
:issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue)
@@ -39,6 +46,7 @@ class Mailer < ActionMailer::Base
'Issue-Id' => issue.id, 'Issue-Id' => issue.id,
'Issue-Author' => issue.author.login 'Issue-Author' => issue.author.login
redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to
@author = journal.user
recipients issue.recipients recipients issue.recipients
# Watchers in cc # Watchers in cc
cc(issue.watcher_recipients - @recipients) cc(issue.watcher_recipients - @recipients)
@@ -73,6 +81,9 @@ class Mailer < ActionMailer::Base
added_to = '' added_to = ''
added_to_url = '' added_to_url = ''
case container.class.name case container.class.name
when 'Project'
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container)
added_to = "#{l(:label_project)}: #{container}"
when 'Version' when 'Version'
added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id) added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id)
added_to = "#{l(:label_version)}: #{container.name}" added_to = "#{l(:label_version)}: #{container.name}"
@@ -122,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') :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc')
end 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) def lost_password(token)
set_language_if_valid(token.user.language) set_language_if_valid(token.user.language)
recipients token.user.mail recipients token.user.mail
@@ -184,16 +204,12 @@ class Mailer < ActionMailer::Base
set_language_if_valid Setting.default_language set_language_if_valid Setting.default_language
from Setting.mail_from 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 # Common headers
headers 'X-Mailer' => 'Redmine', headers 'X-Mailer' => 'Redmine',
'X-Redmine-Host' => Setting.host_name, 'X-Redmine-Host' => Setting.host_name,
'X-Redmine-Site' => Setting.app_title 'X-Redmine-Site' => Setting.app_title,
'Precedence' => 'bulk',
'Auto-Submitted' => 'auto-generated'
end end
# Appends a Redmine header field (name is prepended with 'X-Redmine-') # Appends a Redmine header field (name is prepended with 'X-Redmine-')
@@ -205,9 +221,10 @@ class Mailer < ActionMailer::Base
def create_mail def create_mail
# Removes the current user from the recipients and cc # Removes the current user from the recipients and cc
# if he doesn't want to receive notifications about what he does # if he doesn't want to receive notifications about what he does
if User.current.pref[:no_self_notified] @author ||= User.current
recipients.delete(User.current.mail) if recipients if @author.pref[:no_self_notified]
cc.delete(User.current.mail) if cc recipients.delete(@author.mail) if recipients
cc.delete(@author.mail) if cc
end end
# Blind carbon copy recipients # Blind carbon copy recipients
if Setting.bcc_recipients? if Setting.bcc_recipients?
+2 -2
View File
@@ -19,11 +19,11 @@ class Message < ActiveRecord::Base
belongs_to :board belongs_to :board
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC"
has_many :attachments, :as => :container, :dependent => :destroy acts_as_attachable
belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id' belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id'
acts_as_searchable :columns => ['subject', 'content'], acts_as_searchable :columns => ['subject', 'content'],
:include => {:board, :project}, :include => {:board => :project},
:project_key => 'project_id', :project_key => 'project_id',
:date_column => "#{table_name}.created_on" :date_column => "#{table_name}.created_on"
acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
+1 -1
View File
@@ -24,7 +24,7 @@ class News < ActiveRecord::Base
validates_length_of :title, :maximum => 60 validates_length_of :title, :maximum => 60
validates_length_of :summary, :maximum => 255 validates_length_of :summary, :maximum => 255
acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project
acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}}
acts_as_activity_provider :find_options => {:include => [:project, :author]}, acts_as_activity_provider :find_options => {:include => [:project, :author]},
:author_key => :author_id :author_key => :author_id
+3 -1
View File
@@ -44,6 +44,8 @@ class Project < ActiveRecord::Base
:association_foreign_key => 'custom_field_id' :association_foreign_key => 'custom_field_id'
acts_as_tree :order => "name", :counter_cache => true acts_as_tree :order => "name", :counter_cache => true
acts_as_attachable :view_permission => :view_files,
:delete_permission => :manage_files
acts_as_customizable acts_as_customizable
acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil
@@ -58,7 +60,7 @@ class Project < ActiveRecord::Base
validates_associated :repository, :wiki validates_associated :repository, :wiki
validates_length_of :name, :maximum => 30 validates_length_of :name, :maximum => 30
validates_length_of :homepage, :maximum => 255 validates_length_of :homepage, :maximum => 255
validates_length_of :identifier, :in => 3..20 validates_length_of :identifier, :in => 1..20
validates_format_of :identifier, :with => /^[a-z0-9\-]*$/ validates_format_of :identifier, :with => /^[a-z0-9\-]*$/
before_destroy :delete_all_members before_destroy :delete_all_members
+7 -3
View File
@@ -93,6 +93,7 @@ class Query < ActiveRecord::Base
cattr_reader :operators_by_filter_type cattr_reader :operators_by_filter_type
@@available_columns = [ @@available_columns = [
QueryColumn.new(:project, :sortable => "#{Project.table_name}.name"),
QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position"), QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position"),
QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position"), QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position"),
QueryColumn.new(:priority, :sortable => "#{Enumeration.table_name}.position", :default_order => 'desc'), QueryColumn.new(:priority, :sortable => "#{Enumeration.table_name}.position", :default_order => 'desc'),
@@ -234,7 +235,10 @@ class Query < ActiveRecord::Base
def columns def columns
if has_default_columns? if has_default_columns?
available_columns.select {|c| Setting.issue_list_default_columns.include?(c.name.to_s) } available_columns.select do |c|
# Adds the project column by default for cross-project lists
Setting.issue_list_default_columns.include?(c.name.to_s) || (c.name == :project && project.nil?)
end
else else
# preserve the column_names order # preserve the column_names order
column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact column_names.collect {|name| available_columns.find {|col| col.name == name}}.compact
@@ -364,9 +368,9 @@ class Query < ActiveRecord::Base
Time.now.at_beginning_of_week Time.now.at_beginning_of_week
sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)] sql = "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date(from), connection.quoted_date(from + 7.days)]
when "~" when "~"
sql = "#{db_table}.#{db_field} LIKE '%#{connection.quote_string(value.first)}%'" sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
when "!~" when "!~"
sql = "#{db_table}.#{db_field} NOT LIKE '%#{connection.quote_string(value.first)}%'" sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'"
end end
return sql return sql
+4 -4
View File
@@ -20,7 +20,7 @@ require 'redmine/scm/adapters/subversion_adapter'
class Repository::Subversion < Repository class Repository::Subversion < Repository
attr_protected :root_url attr_protected :root_url
validates_presence_of :url validates_presence_of :url
validates_format_of :url, :with => /^(http|https|svn|svn\+ssh|file):\/\/.+/i validates_format_of :url, :with => /^(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i
def scm_adapter def scm_adapter
Redmine::Scm::Adapters::SubversionAdapter Redmine::Scm::Adapters::SubversionAdapter
@@ -54,8 +54,8 @@ class Repository::Subversion < Repository
# loads changesets by batches of 200 # loads changesets by batches of 200
identifier_to = [identifier_from + 199, scm_revision].min identifier_to = [identifier_from + 199, scm_revision].min
revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true) revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
transaction do revisions.reverse_each do |revision|
revisions.reverse_each do |revision| transaction do
changeset = Changeset.create(:repository => self, changeset = Changeset.create(:repository => self,
:revision => revision.identifier, :revision => revision.identifier,
:committer => revision.author, :committer => revision.author,
@@ -68,7 +68,7 @@ class Repository::Subversion < Repository
:path => change[:path], :path => change[:path],
:from_path => change[:from_path], :from_path => change[:from_path],
:from_revision => change[:from_revision]) :from_revision => change[:from_revision])
end end unless changeset.new_record?
end end
end unless revisions.nil? end unless revisions.nil?
identifier_from = identifier_to + 1 identifier_from = identifier_to + 1
+2 -2
View File
@@ -31,9 +31,9 @@ class Role < ActiveRecord::Base
raise "Can not copy workflow from a #{role.class}" unless role.is_a?(Role) raise "Can not copy workflow from a #{role.class}" unless role.is_a?(Role)
raise "Can not copy workflow from/to an unsaved role" if proxy_owner.new_record? || role.new_record? raise "Can not copy workflow from/to an unsaved role" if proxy_owner.new_record? || role.new_record?
clear clear
connection.insert "INSERT INTO workflows (tracker_id, old_status_id, new_status_id, role_id)" + connection.insert "INSERT INTO #{Workflow.table_name} (tracker_id, old_status_id, new_status_id, role_id)" +
" SELECT tracker_id, old_status_id, new_status_id, #{proxy_owner.id}" + " SELECT tracker_id, old_status_id, new_status_id, #{proxy_owner.id}" +
" FROM workflows" + " FROM #{Workflow.table_name}" +
" WHERE role_id = #{role.id}" " WHERE role_id = #{role.id}"
end end
end end
+2 -2
View File
@@ -32,7 +32,7 @@ class TimeEntry < ActiveRecord::Base
:description => :comments :description => :comments
validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
validates_numericality_of :hours, :allow_nil => true validates_numericality_of :hours, :allow_nil => true, :message => :activerecord_error_invalid
validates_length_of :comments, :maximum => 255, :allow_nil => true validates_length_of :comments, :maximum => 255, :allow_nil => true
def after_initialize def after_initialize
@@ -54,7 +54,7 @@ class TimeEntry < ActiveRecord::Base
end end
def hours=(h) def hours=(h)
write_attribute :hours, (h.is_a?(String) ? h.to_hours : h) write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h)
end end
# tyear, tmonth, tweek assigned where setting spent_on attributes # tyear, tmonth, tweek assigned where setting spent_on attributes
+5 -4
View File
@@ -15,8 +15,11 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'rails_generator/secret_key_generator'
class Token < ActiveRecord::Base class Token < ActiveRecord::Base
belongs_to :user belongs_to :user
validates_uniqueness_of :value
@@validity_time = 1.day @@validity_time = 1.day
@@ -36,9 +39,7 @@ class Token < ActiveRecord::Base
private private
def self.generate_token_value def self.generate_token_value
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a s = Rails::SecretKeyGenerator.new(object_id).generate_secret
token_value = '' s[0, 40]
40.times { |i| token_value << chars[rand(chars.size-1)] }
token_value
end end
end end
+2 -2
View File
@@ -23,9 +23,9 @@ class Tracker < ActiveRecord::Base
raise "Can not copy workflow from a #{tracker.class}" unless tracker.is_a?(Tracker) raise "Can not copy workflow from a #{tracker.class}" unless tracker.is_a?(Tracker)
raise "Can not copy workflow from/to an unsaved tracker" if proxy_owner.new_record? || tracker.new_record? raise "Can not copy workflow from/to an unsaved tracker" if proxy_owner.new_record? || tracker.new_record?
clear clear
connection.insert "INSERT INTO workflows (tracker_id, old_status_id, new_status_id, role_id)" + connection.insert "INSERT INTO #{Workflow.table_name} (tracker_id, old_status_id, new_status_id, role_id)" +
" SELECT #{proxy_owner.id}, old_status_id, new_status_id, role_id" + " SELECT #{proxy_owner.id}, old_status_id, new_status_id, role_id" +
" FROM workflows" + " FROM #{Workflow.table_name}" +
" WHERE tracker_id = #{tracker.id}" " WHERE tracker_id = #{tracker.id}"
end end
end end
+8 -2
View File
@@ -175,8 +175,14 @@ class User < ActiveRecord::Base
end end
def self.find_by_autologin_key(key) def self.find_by_autologin_key(key)
token = Token.find_by_action_and_value('autologin', key) tokens = Token.find_all_by_action_and_value('autologin', key)
token && (token.created_on > Setting.autologin.to_i.day.ago) && token.user.active? ? token.user : nil # Make sure there's only 1 token that matches the key
if tokens.size == 1
token = tokens.first
if (token.created_on > Setting.autologin.to_i.day.ago) && token.user && token.user.active?
token.user
end
end
end end
# Makes find_by_mail case-insensitive # Makes find_by_mail case-insensitive
+2 -1
View File
@@ -19,7 +19,8 @@ class Version < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
belongs_to :project belongs_to :project
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
has_many :attachments, :as => :container, :dependent => :destroy acts_as_attachable :view_permission => :view_files,
:delete_permission => :manage_files
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name, :scope => [:project_id] validates_uniqueness_of :name, :scope => [:project_id]
+1
View File
@@ -22,6 +22,7 @@ class WikiContent < ActiveRecord::Base
belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id' belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :text validates_presence_of :text
validates_length_of :comments, :maximum => 255, :allow_nil => true
acts_as_versioned acts_as_versioned
class Version class Version
+5 -1
View File
@@ -21,7 +21,7 @@ require 'enumerator'
class WikiPage < ActiveRecord::Base class WikiPage < ActiveRecord::Base
belongs_to :wiki belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
has_many :attachments, :as => :container, :dependent => :destroy acts_as_attachable :delete_permission => :delete_wiki_pages_attachments
acts_as_tree :order => 'title' acts_as_tree :order => 'title'
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"}, acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"},
@@ -111,6 +111,10 @@ class WikiPage < ActiveRecord::Base
def editable_by?(usr) def editable_by?(usr)
!protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project)
end end
def attachments_deletable?(usr=User.current)
editable_by?(usr) && super(usr)
end
def parent_title def parent_title
@parent_title || (self.parent && self.parent.pretty_title) @parent_title || (self.parent && self.parent.pretty_title)
+2
View File
@@ -29,6 +29,7 @@
<% end %> <% end %>
</ul> </ul>
<% end %> <% end %>
<%= call_hook :view_account_left_bottom, :user => @user %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
@@ -64,6 +65,7 @@
<%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %> <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %>
<% end %> <% end %>
<% end %> <% end %>
<%= call_hook :view_account_right_bottom, :user => @user %>
</div> </div>
<% html_title @user.name %> <% html_title @user.name %>
+2 -1
View File
@@ -4,7 +4,8 @@
<table class="list"> <table class="list">
<tr class="odd"><td><%= l(:text_default_administrator_account_changed) %></td><td><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> <tr class="odd"><td><%= l(:text_default_administrator_account_changed) %></td><td><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
<tr class="even"><td><%= l(:text_file_repository_writable) %></td><td><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> <tr class="even"><td><%= l(:text_file_repository_writable) %> (<%= Attachment.storage_path %>)</td><td><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
<tr class="even"><td><%= l(:text_plugin_assets_writable) %> (<%= Engines.public_directory %>)</td><td><%= image_tag (@flags[:plugin_assets_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
<tr class="odd"><td><%= l(:text_rmagick_available) %></td><td><%= image_tag (@flags[:rmagick_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> <tr class="odd"><td><%= l(:text_rmagick_available) %></td><td><%= image_tag (@flags[:rmagick_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
</table> </table>
+3 -3
View File
@@ -3,14 +3,14 @@
<p><%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> <p><%= link_to_attachment attachment, :class => 'icon icon-attachment' -%>
<%= h(" - #{attachment.description}") unless attachment.description.blank? %> <%= h(" - #{attachment.description}") unless attachment.description.blank? %>
<span class="size">(<%= number_to_human_size attachment.filesize %>)</span> <span class="size">(<%= number_to_human_size attachment.filesize %>)</span>
<% if options[:delete_url] %> <% if options[:deletable] %>
<%= link_to image_tag('delete.png'), options[:delete_url].update({:attachment_id => attachment}), <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment},
:confirm => l(:text_are_you_sure), :confirm => l(:text_are_you_sure),
:method => :post, :method => :post,
:class => 'delete', :class => 'delete',
:title => l(:button_delete) %> :title => l(:button_delete) %>
<% end %> <% end %>
<% unless options[:no_author] %> <% if options[:author] %>
<span class="author"><%= attachment.author %>, <%= format_time(attachment.created_on) %></span> <span class="author"><%= attachment.author %>, <%= format_time(attachment.created_on) %></span>
<% end %> <% end %>
</p> </p>
+1 -1
View File
@@ -11,7 +11,7 @@ while day <= calendar.enddt %>
<p class="day-num"><%= day.day %></p> <p class="day-num"><%= day.day %></p>
<% calendar.events_on(day).each do |i| %> <% calendar.events_on(day).each do |i| %>
<% if i.is_a? Issue %> <% if i.is_a? Issue %>
<div class="tooltip"> <div class="<%= css_issue_classes(i) %> tooltip">
<%= if day == i.start_date && day == i.due_date <%= if day == i.start_date && day == i.due_date
image_tag('arrow_bw.png') image_tag('arrow_bw.png')
elsif day == i.start_date elsif day == i.start_date
+1 -1
View File
@@ -3,7 +3,7 @@
<tbody> <tbody>
<% line_num = 1 %> <% line_num = 1 %>
<% syntax_highlight(filename, to_utf8(content)).each_line do |line| %> <% 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 %> <% line_num += 1 %>
<% end %> <% end %>
</tbody> </tbody>
+4 -4
View File
@@ -1,8 +1,8 @@
xml.instruct! xml.instruct!
xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
xml.title truncate_single_line(@title, 100) xml.title truncate_single_line(@title, 100)
xml.link "rel" => "self", "href" => url_for(params.merge({:format => nil, :only_path => false})) xml.link "rel" => "self", "href" => url_for(params.merge(:only_path => false))
xml.link "rel" => "alternate", "href" => url_for(:controller => 'welcome', :only_path => false) xml.link "rel" => "alternate", "href" => url_for(params.merge(:only_path => false, :format => nil, :key => nil))
xml.id url_for(:controller => 'welcome', :only_path => false) xml.id url_for(:controller => 'welcome', :only_path => false)
xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema)
xml.author { xml.name "#{Setting.app_title}" } xml.author { xml.name "#{Setting.app_title}" }
@@ -21,10 +21,10 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
author = item.event_author if item.respond_to?(:event_author) author = item.event_author if item.respond_to?(:event_author)
xml.author do xml.author do
xml.name(author) xml.name(author)
xml.email(author.mail) if author.respond_to?(:mail) && !author.mail.blank? xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail
end if author end if author
xml.content "type" => "html" do xml.content "type" => "html" do
xml.text! textilizable(item.event_description) xml.text! textilizable(item, :event_description, :only_path => false)
end end
end end
end end
+2
View File
@@ -82,6 +82,7 @@ function deleteValueField(e) {
<% end %> <% end %>
</p> </p>
<p><%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %></p> <p><%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %></p>
<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %>
</div> </div>
<div class="box"> <div class="box">
@@ -109,5 +110,6 @@ when "IssueCustomField" %>
<p><%= f.check_box :is_required %></p> <p><%= f.check_box :is_required %></p>
<% end %> <% end %>
<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
</div> </div>
<%= javascript_tag "toggle_custom_field_format();" %> <%= javascript_tag "toggle_custom_field_format();" %>
+1 -1
View File
@@ -12,7 +12,7 @@
</div> </div>
<h3><%= l(:label_attachment_plural) %></h3> <h3><%= l(:label_attachment_plural) %></h3>
<%= link_to_attachments @attachments, :delete_url => (authorize_for('documents', 'destroy_attachment') ? {:controller => 'documents', :action => 'destroy_attachment', :id => @document} : nil) %> <%= link_to_attachments @document %>
<% if authorize_for('documents', 'add_attachment') %> <% if authorize_for('documents', 'add_attachment') %>
<p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
+3 -1
View File
@@ -11,5 +11,7 @@
<p><label for="issue_status_is_default"><%=l(:field_is_default)%></label> <p><label for="issue_status_is_default"><%=l(:field_is_default)%></label>
<%= check_box 'issue_status', 'is_default' %></p> <%= check_box 'issue_status', 'is_default' %></p>
<%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %>
<!--[eoform:issue_status]--> <!--[eoform:issue_status]-->
</div> </div>
+11 -1
View File
@@ -8,7 +8,7 @@
<div id="issue_descr_fields" <%= 'style="display:none"' unless @issue.new_record? || @issue.errors.any? %>> <div id="issue_descr_fields" <%= 'style="display:none"' unless @issue.new_record? || @issue.errors.any? %>>
<p><%= f.text_field :subject, :size => 80, :required => true %></p> <p><%= f.text_field :subject, :size => 80, :required => true %></p>
<p><%= f.text_area :description, :required => true, <p><%= f.text_area :description,
:cols => 60, :cols => 60,
:rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min),
:accesskey => accesskey(:edit), :accesskey => accesskey(:edit),
@@ -24,11 +24,13 @@
<p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p> <p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p>
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p> <p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
<% unless @project.issue_categories.empty? %>
<p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> <p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
<%= prompt_to_remote(l(:label_issue_category_new), <%= prompt_to_remote(l(:label_issue_category_new),
l(:label_issue_category_new), 'category[name]', l(:label_issue_category_new), 'category[name]',
{:controller => 'projects', :action => 'add_issue_category', :id => @project}, {:controller => 'projects', :action => 'add_issue_category', :id => @project},
:class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p> :class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p>
<% end %>
<%= content_tag('p', f.select(:fixed_version_id, <%= content_tag('p', f.select(:fixed_version_id,
(@project.versions.sort.collect {|v| [v.name, v.id]}), (@project.versions.sort.collect {|v| [v.name, v.id]}),
{ :include_blank => true })) unless @project.versions.empty? %> { :include_blank => true })) unless @project.versions.empty? %>
@@ -48,6 +50,14 @@
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p> <p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
<% end %> <% end %>
<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%>
<p><label><%= l(:label_issue_watchers) %></label>
<% @issue.project.users.sort.each do |user| -%>
<label class="floating"><%= check_box_tag 'issue[watcher_user_ids][]', user.id, @issue.watcher_user_ids.include?(user.id) %> <%=h user %></label>
<% end -%>
</p>
<% end %>
<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> <%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %>
<%= wikitoolbar_for 'issue_description' %> <%= wikitoolbar_for 'issue_description' %>
+2 -2
View File
@@ -7,8 +7,8 @@
<%= call_hook(:view_issues_sidebar_issues_bottom) %> <%= call_hook(:view_issues_sidebar_issues_bottom) %>
<% planning_links = [] <% planning_links = []
planning_links << link_to(l(:label_calendar), :action => 'calendar', :project_id => @project) if User.current.allowed_to?(:view_calendar, @project, :global => true) planning_links << link_to(l(:label_calendar), :controller => 'issues', :action => 'calendar', :project_id => @project) if User.current.allowed_to?(:view_calendar, @project, :global => true)
planning_links << link_to(l(:label_gantt), :action => 'gantt', :project_id => @project) if User.current.allowed_to?(:view_gantt, @project, :global => true) planning_links << link_to(l(:label_gantt), :controller => 'issues', :action => 'gantt', :project_id => @project) if User.current.allowed_to?(:view_gantt, @project, :global => true)
%> %>
<% unless planning_links.empty? %> <% unless planning_links.empty? %>
<h3><%= l(:label_planning) %></h3> <h3><%= l(:label_planning) %></h3>
+1
View File
@@ -44,6 +44,7 @@
<fieldset><legend><%= l(:field_notes) %></legend> <fieldset><legend><%= l(:field_notes) %></legend>
<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %>
<%= wikitoolbar_for 'notes' %> <%= wikitoolbar_for 'notes' %>
</fieldset>
</div> </div>
<p><%= submit_tag l(:button_submit) %> <p><%= submit_tag l(:button_submit) %>
+2 -2
View File
@@ -15,7 +15,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
xml.updated change.created_on.xmlschema xml.updated change.created_on.xmlschema
xml.author do xml.author do
xml.name change.user.name xml.name change.user.name
xml.email(change.user.mail) xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail
end end
xml.content "type" => "html" do xml.content "type" => "html" do
xml.text! '<ul>' xml.text! '<ul>'
@@ -23,7 +23,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do
xml.text! '<li>' + show_detail(detail, false) + '</li>' xml.text! '<li>' + show_detail(detail, false) + '</li>'
end end
xml.text! '</ul>' xml.text! '</ul>'
xml.text! textilizable(change.notes) unless change.notes.blank? xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank?
end end
end end
end end
+4
View File
@@ -1,4 +1,6 @@
<ul> <ul>
<%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %>
<% if !@issue.nil? -%> <% if !@issue.nil? -%>
<li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue}, <li><%= context_menu_link l(:button_edit), {:controller => 'issues', :action => 'edit', :id => @issue},
:class => 'icon-edit', :disabled => !@can[:edit] %></li> :class => 'icon-edit', :disabled => !@can[:edit] %></li>
@@ -87,4 +89,6 @@
:class => 'icon-move', :disabled => !@can[:move] %></li> :class => 'icon-move', :disabled => !@can[:move] %></li>
<li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)}, <li><%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)},
:method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %></li> :method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %></li>
<%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %>
</ul> </ul>
-188
View File
@@ -1,188 +0,0 @@
<%
pdf=IfpdfHelper::IFPDF.new(current_language)
pdf.SetTitle("#{l(:label_gantt)} #{@project}")
pdf.AliasNbPages
pdf.footer_date = format_date(Date.today)
pdf.AddPage("L")
pdf.SetFontStyle('B',12)
pdf.SetX(15)
pdf.Cell(70, 20, @project.to_s)
pdf.Ln
pdf.SetFontStyle('B',9)
subject_width = 70
header_heigth = 5
headers_heigth = header_heigth
show_weeks = false
show_days = false
if @gantt.months < 7
show_weeks = true
headers_heigth = 2*header_heigth
if @gantt.months < 3
show_days = true
headers_heigth = 3*header_heigth
end
end
g_width = 210
zoom = (g_width) / (@gantt.date_to - @gantt.date_from + 1)
g_height = 120
t_height = g_height + headers_heigth
y_start = pdf.GetY
#
# Months headers
#
month_f = @gantt.date_from
left = subject_width
height = header_heigth
@gantt.months.times do
width = ((month_f >> 1) - month_f) * zoom
pdf.SetY(y_start)
pdf.SetX(left)
pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C")
left = left + width
month_f = month_f >> 1
end
#
# Weeks headers
#
if show_weeks
left = subject_width
height = header_heigth
if @gantt.date_from.cwday == 1
# @gantt.date_from is monday
week_f = @gantt.date_from
else
# find next monday after @gantt.date_from
week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1)
width = (7 - @gantt.date_from.cwday + 1) * zoom-1
pdf.SetY(y_start + header_heigth)
pdf.SetX(left)
pdf.Cell(width + 1, height, "", "LTR")
left = left + width+1
end
while week_f <= @gantt.date_to
width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom : (@gantt.date_to - week_f + 1) * zoom
pdf.SetY(y_start + header_heigth)
pdf.SetX(left)
pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C")
left = left + width
week_f = week_f+7
end
end
#
# Days headers
#
if show_days
left = subject_width
height = header_heigth
wday = @gantt.date_from.cwday
pdf.SetFontStyle('B',7)
(@gantt.date_to - @gantt.date_from + 1).to_i.times do
width = zoom
pdf.SetY(y_start + 2 * header_heigth)
pdf.SetX(left)
pdf.Cell(width, height, day_name(wday).first, "LTR", 0, "C")
left = left + width
wday = wday + 1
wday = 1 if wday > 7
end
end
pdf.SetY(y_start)
pdf.SetX(15)
pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1)
#
# Tasks
#
top = headers_heigth + y_start
pdf.SetFontStyle('B',7)
@gantt.events.each do |i|
pdf.SetY(top)
pdf.SetX(15)
if i.is_a? Issue
pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR")
else
pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR")
end
pdf.SetY(top)
pdf.SetX(subject_width)
pdf.Cell(g_width, 5, "", "LR")
pdf.SetY(top+1.5)
if i.is_a? Issue
i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from )
i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to )
i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor
i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date )
i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date )
i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today
i_left = ((i_start_date - @gantt.date_from)*zoom)
i_width = ((i_end_date - i_start_date + 1)*zoom)
d_width = ((i_done_date - i_start_date)*zoom)
l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date
l_width ||= 0
pdf.SetX(subject_width + i_left)
pdf.SetFillColor(200,200,200)
pdf.Cell(i_width, 2, "", 0, 0, "", 1)
if l_width > 0
pdf.SetY(top+1.5)
pdf.SetX(subject_width + i_left)
pdf.SetFillColor(255,100,100)
pdf.Cell(l_width, 2, "", 0, 0, "", 1)
end
if d_width > 0
pdf.SetY(top+1.5)
pdf.SetX(subject_width + i_left)
pdf.SetFillColor(100,100,255)
pdf.Cell(d_width, 2, "", 0, 0, "", 1)
end
pdf.SetY(top+1.5)
pdf.SetX(subject_width + i_left + i_width)
pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%")
else
i_left = ((i.start_date - @gantt.date_from)*zoom)
pdf.SetX(subject_width + i_left)
pdf.SetFillColor(50,200,50)
pdf.Cell(2, 2, "", 0, 0, "", 1)
pdf.SetY(top+1.5)
pdf.SetX(subject_width + i_left + 3)
pdf.Cell(30, 2, "#{i.name}")
end
top = top + 5
pdf.SetDrawColor(200, 200, 200)
pdf.Line(15, top, subject_width+g_width, top)
if pdf.GetY() > 180
pdf.AddPage("L")
top = 20
pdf.Line(15, top, subject_width+g_width, top)
end
pdf.SetDrawColor(0, 0, 0)
end
pdf.Line(15, top, subject_width+g_width, top)
%>
<%= pdf.Output %>
-50
View File
@@ -1,50 +0,0 @@
<% pdf=IfpdfHelper::IFPDF.new(current_language)
title = @project ? "#{@project.name} - #{l(:label_issue_plural)}" : "#{l(:label_issue_plural)}"
pdf.SetTitle(title)
pdf.AliasNbPages
pdf.footer_date = format_date(Date.today)
pdf.AddPage("L")
row_height = 7
#
# title
#
pdf.SetFontStyle('B',11)
pdf.Cell(190,10, title)
pdf.Ln
#
# headers
#
pdf.SetFontStyle('B',10)
pdf.SetFillColor(230, 230, 230)
pdf.Cell(15, row_height, "#", 0, 0, 'L', 1)
pdf.Cell(30, row_height, l(:field_tracker), 0, 0, 'L', 1)
pdf.Cell(30, row_height, l(:field_status), 0, 0, 'L', 1)
pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1)
pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1)
pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1)
pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1)
pdf.Line(10, pdf.GetY, 287, pdf.GetY)
pdf.Ln
pdf.Line(10, pdf.GetY, 287, pdf.GetY)
pdf.SetY(pdf.GetY() + 1)
#
# rows
#
pdf.SetFontStyle('',9)
pdf.SetFillColor(255, 255, 255)
@issues.each do |issue|
pdf.Cell(15, row_height, issue.id.to_s, 0, 0, 'L', 1)
pdf.Cell(30, row_height, issue.tracker.name, 0, 0, 'L', 1)
pdf.Cell(30, row_height, issue.status.name, 0, 0, 'L', 1)
pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1)
pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.name : '', 0, 0, 'L', 1)
pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1)
pdf.MultiCell(0, row_height, (@project == issue.project ? issue.subject : "#{issue.project.name} - #{issue.subject}"))
pdf.Line(10, pdf.GetY, 287, pdf.GetY)
pdf.SetY(pdf.GetY() + 1)
end
%>
<%= pdf.Output %>
+1 -1
View File
@@ -42,6 +42,7 @@
<% else %> <% else %>
<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>
<p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p> <p class="pagination"><%= pagination_links_full @issue_pages, @issue_count %></p>
<% end %>
<p class="other-formats"> <p class="other-formats">
<%= l(:label_export_to) %> <%= l(:label_export_to) %>
@@ -50,7 +51,6 @@
<span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span> <span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
</p> </p>
<% end %> <% end %>
<% end %>
<% content_for :sidebar do %> <% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %> <%= render :partial => 'issues/sidebar' %>
+7
View File
@@ -7,6 +7,7 @@
<%= render :partial => 'issues/form', :locals => {:f => f} %> <%= render :partial => 'issues/form', :locals => {:f => f} %>
</div> </div>
<%= submit_tag l(:button_create) %> <%= submit_tag l(:button_create) %>
<%= submit_tag l(:button_create_and_continue), :name => 'continue' %>
<%= link_to_remote l(:label_preview), <%= link_to_remote l(:label_preview),
{ :url => { :controller => 'issues', :action => 'preview', :project_id => @project }, { :url => { :controller => 'issues', :action => 'preview', :project_id => @project },
:method => 'post', :method => 'post',
@@ -14,6 +15,12 @@
:with => "Form.serialize('issue-form')", :with => "Form.serialize('issue-form')",
:complete => "Element.scrollTo('preview')" :complete => "Element.scrollTo('preview')"
}, :accesskey => accesskey(:preview) %> }, :accesskey => accesskey(:preview) %>
<%= javascript_tag "Form.Element.focus('issue_subject');" %>
<% end %> <% end %>
<div id="preview" class="wiki"></div> <div id="preview" class="wiki"></div>
<% content_for :header_tags do %>
<%= stylesheet_link_tag 'scm' %>
<% end %>
-126
View File
@@ -1,126 +0,0 @@
<% pdf=IfpdfHelper::IFPDF.new(current_language)
pdf.SetTitle("#{@project.name} - ##{@issue.tracker.name} #{@issue.id}")
pdf.AliasNbPages
pdf.footer_date = format_date(Date.today)
pdf.AddPage
pdf.SetFontStyle('B',11)
pdf.Cell(190,10, "#{@issue.project} - #{@issue.tracker} # #{@issue.id}: #{@issue.subject}")
pdf.Ln
y0 = pdf.GetY
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_status) + ":","LT")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, @issue.status.name,"RT")
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_priority) + ":","LT")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, @issue.priority.name,"RT")
pdf.Ln
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_author) + ":","L")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, @issue.author.name,"R")
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_category) + ":","L")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, (@issue.category ? @issue.category.name : "-"),"R")
pdf.Ln
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_created_on) + ":","L")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, format_date(@issue.created_on),"R")
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_assigned_to) + ":","L")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, (@issue.assigned_to ? @issue.assigned_to.name : "-"),"R")
pdf.Ln
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_updated_on) + ":","LB")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, format_date(@issue.updated_on),"RB")
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_due_date) + ":","LB")
pdf.SetFontStyle('',9)
pdf.Cell(60,5, format_date(@issue.due_date),"RB")
pdf.Ln
for custom_value in @issue.custom_values
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, custom_value.custom_field.name + ":","L")
pdf.SetFontStyle('',9)
pdf.MultiCell(155,5, (show_value custom_value),"R")
end
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_subject) + ":","LTB")
pdf.SetFontStyle('',9)
pdf.Cell(155,5, @issue.subject,"RTB")
pdf.Ln
pdf.SetFontStyle('B',9)
pdf.Cell(35,5, l(:field_description) + ":")
pdf.SetFontStyle('',9)
pdf.MultiCell(155,5, @issue.description,"BR")
pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY)
pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY)
pdf.Ln
if @issue.changesets.any? && User.current.allowed_to?(:view_changesets, @issue.project)
pdf.SetFontStyle('B',9)
pdf.Cell(190,5, l(:label_associated_revisions), "B")
pdf.Ln
for changeset in @issue.changesets
pdf.SetFontStyle('B',8)
pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.author.to_s)
pdf.Ln
unless changeset.comments.blank?
pdf.SetFontStyle('',8)
pdf.MultiCell(190,5, changeset.comments)
end
pdf.Ln
end
end
pdf.SetFontStyle('B',9)
pdf.Cell(190,5, l(:label_history), "B")
pdf.Ln
for journal in @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC")
pdf.SetFontStyle('B',8)
pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name)
pdf.Ln
pdf.SetFontStyle('I',8)
for detail in journal.details
pdf.Cell(190,5, "- " + show_detail(detail, true))
pdf.Ln
end
if journal.notes?
pdf.SetFontStyle('',8)
pdf.MultiCell(190,5, journal.notes)
end
pdf.Ln
end
if @issue.attachments.any?
pdf.SetFontStyle('B',9)
pdf.Cell(190,5, l(:label_attachment_plural), "B")
pdf.Ln
for attachment in @issue.attachments
pdf.SetFontStyle('',8)
pdf.Cell(80,5, attachment.filename)
pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R")
pdf.Cell(65,5, attachment.author.name,0,0,"R")
pdf.Ln
end
end
%>
<%= pdf.Output %>
+8 -8
View File
@@ -9,7 +9,7 @@
<h2><%= @issue.tracker.name %> #<%= @issue.id %></h2> <h2><%= @issue.tracker.name %> #<%= @issue.id %></h2>
<div class="<%= css_issue_classes(@issue) %>"> <div class="<%= css_issue_classes(@issue) %> details">
<%= avatar(@issue.author, :size => "64") %> <%= avatar(@issue.author, :size => "64") %>
<h3><%=h @issue.subject %></h3> <h3><%=h @issue.subject %></h3>
<p class="author"> <p class="author">
@@ -19,11 +19,11 @@
<table width="100%"> <table width="100%">
<tr> <tr>
<td style="width:15%" class="status"><b><%=l(:field_status)%>:</b></td><td style="width:35%" class="status status-<%= @issue.status.name %>"><%= @issue.status.name %></td> <td style="width:15%" class="status"><b><%=l(:field_status)%>:</b></td><td style="width:35%" class="status"><%= @issue.status.name %></td>
<td style="width:15%" class="start-date"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td> <td style="width:15%" class="start-date"><b><%=l(:field_start_date)%>:</b></td><td style="width:35%"><%= format_date(@issue.start_date) %></td>
</tr> </tr>
<tr> <tr>
<td class="priority"><b><%=l(:field_priority)%>:</b></td><td class="priority priority-<%= @issue.priority.name %>"><%= @issue.priority.name %></td> <td class="priority"><b><%=l(:field_priority)%>:</b></td><td class="priority"><%= @issue.priority.name %></td>
<td class="due-date"><b><%=l(:field_due_date)%>:</b></td><td class="due-date"><%= format_date(@issue.due_date) %></td> <td class="due-date"><b><%=l(:field_due_date)%>:</b></td><td class="due-date"><%= format_date(@issue.due_date) %></td>
</tr> </tr>
<tr> <tr>
@@ -45,7 +45,7 @@
</tr> </tr>
<tr> <tr>
<% n = 0 -%> <% n = 0 -%>
<% @issue.custom_values.each do |value| -%> <% @issue.custom_field_values.each do |value| -%>
<td valign="top"><b><%=h value.custom_field.name %>:</b></td><td valign="top"><%= simple_format(h(show_value(value))) %></td> <td valign="top"><b><%=h value.custom_field.name %>:</b></td><td valign="top"><%= simple_format(h(show_value(value))) %></td>
<% n = n + 1 <% n = n + 1
if (n > 1) if (n > 1)
@@ -59,7 +59,7 @@ end %>
<hr /> <hr />
<div class="contextual"> <div class="contextual">
<%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment' %> <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>
</div> </div>
<p><strong><%=l(:field_description)%></strong></p> <p><strong><%=l(:field_description)%></strong></p>
@@ -67,9 +67,9 @@ end %>
<%= textilizable @issue, :description, :attachments => @issue.attachments %> <%= textilizable @issue, :description, :attachments => @issue.attachments %>
</div> </div>
<% if @issue.attachments.any? %> <%= link_to_attachments @issue %>
<%= link_to_attachments @issue.attachments, :delete_url => (authorize_for('issues', 'destroy_attachment') ? {:controller => 'issues', :action => 'destroy_attachment', :id => @issue} : nil) %>
<% end %> <%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %>
<% if authorize_for('issue_relations', 'new') || @issue.relations.any? %> <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
<hr /> <hr />
+2 -2
View File
@@ -3,10 +3,10 @@
<option selected="selected"><%= l(:label_jump_to_a_project) %></option> <option selected="selected"><%= l(:label_jump_to_a_project) %></option>
<option disabled="disabled">---</option> <option disabled="disabled">---</option>
<% user_projects_by_root.keys.sort.each do |root| %> <% user_projects_by_root.keys.sort.each do |root| %>
<%= content_tag('option', h(root.name), :value => url_for(:controller => 'projects', :action => 'show', :id => root)) %> <%= content_tag('option', h(root.name), :value => url_for(:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item)) %>
<% user_projects_by_root[root].sort.each do |project| %> <% user_projects_by_root[root].sort.each do |project| %>
<% next if project == root %> <% next if project == root %>
<%= content_tag('option', ('&#187; ' + h(project.name)), :value => url_for(:controller => 'projects', :action => 'show', :id => project)) %> <%= content_tag('option', ('&#187; ' + h(project.name)), :value => url_for(:controller => 'projects', :action => 'show', :id => project, :jump => current_menu_item)) %>
<% end %> <% end %>
<% end %> <% end %>
</select> </select>
+4 -3
View File
@@ -47,19 +47,20 @@
<%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %> <%= tag('div', {:id => 'main', :class => (has_content?(:sidebar) ? '' : 'nosidebar')}, true) %>
<div id="sidebar"> <div id="sidebar">
<%= yield :sidebar %> <%= yield :sidebar %>
<%= call_hook :view_layouts_base_sidebar %>
</div> </div>
<div id="content"> <div id="content">
<%= content_tag('div', flash[:error], :class => 'flash error') if flash[:error] %> <%= render_flash_messages %>
<%= content_tag('div', flash[:notice], :class => 'flash notice') if flash[:notice] %>
<%= yield %> <%= yield %>
<%= call_hook :view_layouts_base_content %>
</div> </div>
</div> </div>
<div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div> <div id="ajax-indicator" style="display:none;"><span><%= l(:label_loading) %></span></div>
<div id="footer"> <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>
</div> </div>
<%= call_hook :view_layouts_base_body_bottom %> <%= call_hook :view_layouts_base_body_bottom %>
@@ -0,0 +1,2 @@
<p><%= l(:notice_account_activated) %></p>
<p><%= l(:label_login) %>: <%= link_to @login_url, @login_url %></p>
@@ -0,0 +1,2 @@
<%= l(:notice_account_activated) %>
<%= l(:label_login) %>: <%= @login_url %>
+6 -11
View File
@@ -6,17 +6,12 @@ body {
font-size: 0.8em; font-size: 0.8em;
color:#484848; color:#484848;
} }
h1 { h1, h2, h3 { font-family: "Trebuchet MS", Verdana, sans-serif; margin: 0px; }
font-family: "Trebuchet MS", Verdana, sans-serif; h1 { font-size: 1.2em; }
font-size: 1.2em; h2, h3 { font-size: 1.1em; }
margin: 0px; a, a:link, a:visited { color: #2A5685;}
} a:hover, a:active { color: #c61a1a; }
a, a:link, a:visited { a.wiki-anchor { display: none; }
color: #2A5685;
}
a:hover, a:active {
color: #c61a1a;
}
hr { hr {
width: 100%; width: 100%;
height: 1px; height: 1px;
+1 -1
View File
@@ -1,3 +1,3 @@
<%= yield %> <%= yield %>
---------------------------------------- --
<%= Setting.emails_footer %> <%= Setting.emails_footer %>
+1 -1
View File
@@ -2,7 +2,7 @@
<ul> <ul>
<% @issues.each do |issue| -%> <% @issues.each do |issue| -%>
<li><%=h "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %></li> <li><%=h issue.project %> - <%=link_to("#{issue.tracker} ##{issue.id}", :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %></li>
<% end -%> <% end -%>
</ul> </ul>
+2 -2
View File
@@ -15,7 +15,7 @@
<div class="wiki"> <div class="wiki">
<%= textilizable(@topic.content, :attachments => @topic.attachments) %> <%= textilizable(@topic.content, :attachments => @topic.attachments) %>
</div> </div>
<%= link_to_attachments @topic.attachments, :no_author => true %> <%= link_to_attachments @topic, :author => false %>
</div> </div>
<br /> <br />
@@ -31,7 +31,7 @@
<div class="message reply"> <div class="message reply">
<h4><%=h message.subject %> - <%= authoring message.created_on, message.author %></h4> <h4><%=h message.subject %> - <%= authoring message.created_on, message.author %></h4>
<div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div> <div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div>
<%= link_to_attachments message.attachments, :no_author => true %> <%= link_to_attachments message, :author => false %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
+1
View File
@@ -15,6 +15,7 @@
<p><%= f.text_field :lastname, :required => true %></p> <p><%= f.text_field :lastname, :required => true %></p>
<p><%= f.text_field :mail, :required => true %></p> <p><%= f.text_field :mail, :required => true %></p>
<p><%= f.select :language, lang_options_for_select %></p> <p><%= f.select :language, lang_options_for_select %></p>
<%= call_hook(:view_my_account, :user => @user, :form => f) %>
</div> </div>
<%= submit_tag l(:button_save) %> <%= submit_tag l(:button_save) %>
+1 -1
View File
@@ -47,6 +47,6 @@ entries_by_day = entries.group_by(&:spent_on)
</tr> </tr>
<% end -%> <% end -%>
<% end -%> <% end -%>
</tbdoy> </tbody>
</table> </table>
<% end %> <% end %>
+1 -1
View File
@@ -11,7 +11,7 @@
<p><%= f.text_area :description, :rows => 5, :class => 'wiki-edit' %></p> <p><%= f.text_area :description, :rows => 5, :class => 'wiki-edit' %></p>
<p><%= f.text_field :identifier, :required => true, :disabled => @project.identifier_frozen? %> <p><%= f.text_field :identifier, :required => true, :disabled => @project.identifier_frozen? %>
<% unless @project.identifier_frozen? %> <% unless @project.identifier_frozen? %>
<br /><em><%= l(:text_length_between, 3, 20) %> <%= l(:text_project_identifier_info) %></em> <br /><em><%= l(:text_length_between, 1, 20) %> <%= l(:text_project_identifier_info) %></em>
<% end %></p> <% end %></p>
<p><%= f.text_field :homepage, :size => 60 %></p> <p><%= f.text_field :homepage, :size => 60 %></p>
<p><%= f.check_box :is_public %></p> <p><%= f.check_box :is_public %></p>
+3 -1
View File
@@ -46,7 +46,9 @@
<% form_tag({}, :method => :get) do %> <% form_tag({}, :method => :get) do %>
<h3><%= l(:label_activity) %></h3> <h3><%= l(:label_activity) %></h3>
<p><% @activity.event_types.each do |t| %> <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> <% end %></p>
<% if @project && @project.active_children.any? %> <% if @project && @project.active_children.any? %>
<p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p> <p><label><%= check_box_tag 'with_subprojects', 1, @with_subprojects %> <%=l(:label_subproject_plural)%></label></p>
+6 -3
View File
@@ -4,10 +4,13 @@
<div class="box"> <div class="box">
<% form_tag({ :action => 'add_file', :id => @project }, :multipart => true, :class => "tabular") do %> <% form_tag({ :action => 'add_file', :id => @project }, :multipart => true, :class => "tabular") do %>
<p><label for="version_id"><%=l(:field_version)%> <span class="required">*</span></label> <% if @versions.any? %>
<%= select_tag "version_id", options_from_collection_for_select(@versions, "id", "name") %></p> <p><label for="version_id"><%=l(:field_version)%></label>
<%= select_tag "version_id", content_tag('option', '') +
options_from_collection_for_select(@versions, "id", "name") %></p>
<% end %>
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p> <p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
</div> </div>
<%= submit_tag l(:button_add) %> <%= submit_tag l(:button_add) %>
<% end %> <% end %>
+21 -19
View File
@@ -4,39 +4,41 @@
<h2><%=l(:label_attachment_plural)%></h2> <h2><%=l(:label_attachment_plural)%></h2>
<% delete_allowed = authorize_for('versions', 'destroy_file') %> <% delete_allowed = User.current.allowed_to?(:manage_files, @project) %>
<table class="list"> <table class="list files">
<thead><tr> <thead><tr>
<th><%=l(:field_version)%></th>
<%= sort_header_tag('filename', :caption => l(:field_filename)) %> <%= sort_header_tag('filename', :caption => l(:field_filename)) %>
<%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %> <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %>
<%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %> <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %>
<%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %> <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
<th>MD5</th> <th>MD5</th>
<% if delete_allowed %><th></th><% end %> <th></th>
</tr></thead> </tr></thead>
<tbody> <tbody>
<% for version in @versions %> <% @containers.each do |container| %>
<% unless version.attachments.empty? %> <% next if container.attachments.empty? -%>
<tr><th colspan="7" align="left"><span class="icon icon-package"><b><%= version.name %></b></span></th></tr> <% if container.is_a?(Version) -%>
<% for file in version.attachments %> <tr>
<tr class="<%= cycle("odd", "even") %>"> <th colspan="6" align="left">
<td></td> <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %>
<td><%= link_to_attachment file, :download => true, :title => file.description %></td> </th>
<td align="center"><%= format_time(file.created_on) %></td> </tr>
<td align="center"><%= number_to_human_size(file.filesize) %></td> <% end -%>
<td align="center"><%= file.downloads %></td> <% container.attachments.each do |file| %>
<td align="center"><small><%= file.digest %></small></td> <tr class="file <%= cycle("odd", "even") %>">
<% if delete_allowed %> <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"> <td align="center">
<%= link_to_if_authorized image_tag('delete.png'), {:controller => 'versions', :action => 'destroy_file', :id => version, :attachment_id => file}, :confirm => l(:text_are_you_sure), :method => :post %> <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file},
:confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %>
</td> </td>
<% end %>
</tr> </tr>
<% end <% end
reset_cycle %> reset_cycle %>
<% end %>
<% end %> <% end %>
</tbody> </tbody>
</table> </table>
+5
View File
@@ -1,6 +1,8 @@
<h2><%=l(:label_settings)%></h2> <h2><%=l(:label_settings)%></h2>
<% tabs = project_settings_tabs %> <% tabs = project_settings_tabs %>
<% if tabs.any? %>
<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %> <% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %>
<div class="tabs"> <div class="tabs">
@@ -20,5 +22,8 @@
:style => (tab[:name] != selected_tab ? 'display:none' : nil), :style => (tab[:name] != selected_tab ? 'display:none' : nil),
:class => 'tab-content') %> :class => 'tab-content') %>
<% end -%> <% end -%>
<% else %>
<p class="nodata"><%= l(:label_no_data) %></p>
<% end %>
<% html_title(l(:label_settings)) -%> <% html_title(l(:label_settings)) -%>
@@ -17,7 +17,6 @@
<td><%= link_to(version.wiki_page_title, :controller => 'wiki', :page => Wiki.titleize(version.wiki_page_title)) unless version.wiki_page_title.blank? || @project.wiki.nil? %></td> <td><%= link_to(version.wiki_page_title, :controller => 'wiki', :page => Wiki.titleize(version.wiki_page_title)) unless version.wiki_page_title.blank? || @project.wiki.nil? %></td>
<td align="center"><%= link_to_if_authorized l(:button_edit), { :controller => 'versions', :action => 'edit', :id => version }, :class => 'icon icon-edit' %></td> <td align="center"><%= link_to_if_authorized l(:button_edit), { :controller => 'versions', :action => 'edit', :id => version }, :class => 'icon icon-edit' %></td>
<td align="center"><%= link_to_if_authorized l(:button_delete), {:controller => 'versions', :action => 'destroy', :id => version}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %></td> <td align="center"><%= link_to_if_authorized l(:button_delete), {:controller => 'versions', :action => 'destroy', :id => version}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %></td>
</td>
</tr> </tr>
<% end; reset_cycle %> <% end; reset_cycle %>
</tbody> </tbody>
+2
View File
@@ -32,6 +32,7 @@
<p><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 %></p> <p><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 %></p>
</div> </div>
<% end %> <% end %>
<%= call_hook(:view_projects_show_left, :project => @project) %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
@@ -53,6 +54,7 @@
<p><%= link_to l(:label_news_view_all), :controller => 'news', :action => 'index', :project_id => @project %></p> <p><%= link_to l(:label_news_view_all), :controller => 'news', :action => 'index', :project_id => @project %></p>
</div> </div>
<% end %> <% end %>
<%= call_hook(:view_projects_show_right, :project => @project) %>
</div> </div>
<% content_for :sidebar do %> <% content_for :sidebar do %>
@@ -0,0 +1,10 @@
<p>
<% if @repository.supports_cat? %>
<%= link_to_if action_name != 'entry', l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> |
<% end %>
<% if @repository.supports_annotate? %>
<%= link_to_if action_name != 'annotate', l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> |
<% end %>
<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %>
<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %>
</p>
+3 -1
View File
@@ -1,5 +1,7 @@
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2> <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
<p><%= render :partial => 'link_to_functions' %></p>
<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> <% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %>
<div class="autoscroll"> <div class="autoscroll">
@@ -9,7 +11,7 @@
<% syntax_highlight(@path, to_utf8(@annotate.content)).each_line do |line| %> <% syntax_highlight(@path, to_utf8(@annotate.content)).each_line do |line| %>
<% revision = @annotate.revisions[line_num-1] %> <% revision = @annotate.revisions[line_num-1] %>
<tr class="bloc-<%= revision.nil? ? 0 : colors[revision.identifier || revision.revision] %>"> <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"> <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> <%= (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> <td class="author"><%= h(revision.author.to_s.split('<').first) if revision %></td>
+1 -10
View File
@@ -1,15 +1,6 @@
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2> <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %></h2>
<p> <p><%= render :partial => 'link_to_functions' %></p>
<% if @repository.supports_cat? %>
<%= link_to l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> |
<% end %>
<% if @repository.supports_annotate? %>
<%= link_to l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> |
<% end %>
<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %>
<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %>
</p>
<%= render_properties(@properties) %> <%= render_properties(@properties) %>
+2
View File
@@ -1,5 +1,7 @@
<h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2> <h2><%= render :partial => 'navigation', :locals => { :path => @path, :kind => 'file', :revision => @rev } %></h2>
<p><%= render :partial => 'link_to_functions' %></p>
<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> <%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %>
<% content_for :header_tags do %> <% content_for :header_tags do %>
+4 -4
View File
@@ -11,12 +11,12 @@
<%= text_field_tag 'settings[issues_export_limit]', Setting.issues_export_limit, :size => 6 %></p> <%= text_field_tag 'settings[issues_export_limit]', Setting.issues_export_limit, :size => 6 %></p>
</div> </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][]', '' %> <%= 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) %> <label><%= check_box_tag 'settings[issue_list_default_columns][]', column.name, Setting.issue_list_default_columns.include?(column.name.to_s) %>
<%= column.caption %></label> <%= column.caption %></label><br />
<% end %></p> <% end %>
</fieldset> </fieldset>
<%= submit_tag l(:button_save) %> <%= submit_tag l(:button_save) %>
+1 -1
View File
@@ -7,7 +7,7 @@
<h2><%= l(:label_spent_time) %></h2> <h2><%= l(:label_spent_time) %></h2>
<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %> <% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %>
<%= hidden_field_tag 'project_id', params[:project_id] %> <%= hidden_field_tag('project_id', params[:project_id]) if @project %>
<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %> <%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>
<%= render :partial => 'date_range' %> <%= render :partial => 'date_range' %>
<% end %> <% end %>
+1 -1
View File
@@ -10,7 +10,7 @@
<% @criterias.each do |criteria| %> <% @criterias.each do |criteria| %>
<%= hidden_field_tag 'criterias[]', criteria, :id => nil %> <%= hidden_field_tag 'criterias[]', criteria, :id => nil %>
<% end %> <% end %>
<%= hidden_field_tag 'project_id', params[:project_id] %> <%= hidden_field_tag('project_id', params[:project_id]) if @project %>
<%= render :partial => 'date_range' %> <%= render :partial => 'date_range' %>
<p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], <p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'],
+1
View File
@@ -13,6 +13,7 @@
<% end %> <% end %>
<p><%= f.check_box :admin, :disabled => (@user == User.current) %></p> <p><%= f.check_box :admin, :disabled => (@user == User.current) %></p>
<%= call_hook(:view_users_form, :user => @user, :form => f) %>
</div> </div>
<div class="box"> <div class="box">
+2
View File
@@ -4,6 +4,7 @@
<th><%= l(:label_project) %></th> <th><%= l(:label_project) %></th>
<th><%= l(:label_role) %></th> <th><%= l(:label_role) %></th>
<th style="width:15%"></th> <th style="width:15%"></th>
<%= call_hook(:view_users_memberships_table_header, :user => @user )%>
</thead> </thead>
<tbody> <tbody>
<% @memberships.each do |membership| %> <% @memberships.each do |membership| %>
@@ -19,6 +20,7 @@
<td align="center"> <td align="center">
<%= link_to l(:button_delete), {:action => 'destroy_membership', :id => @user, :membership_id => membership }, :method => :post, :class => 'icon icon-del' %> <%= link_to l(:button_delete), {:action => 'destroy_membership', :id => @user, :membership_id => membership }, :method => :post, :class => 'icon icon-del' %>
</td> </td>
<%= call_hook(:view_users_memberships_table_row, :user => @user, :membership => membership, :roles => @roles, :projects => @projects )%>
</tr> </tr>
</tbody> </tbody>
<% end; reset_cycle %> <% end; reset_cycle %>
+1
View File
@@ -1,5 +1,6 @@
<div class="contextual"> <div class="contextual">
<%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => @version}, :class => 'icon icon-edit' %> <%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => @version}, :class => 'icon icon-edit' %>
<%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %>
</div> </div>
<h2><%= h(@version.name) %></h2> <h2><%= h(@version.name) %></h2>
+2
View File
@@ -9,6 +9,7 @@
<%= link_to l(:label_news_view_all), :controller => 'news' %> <%= link_to l(:label_news_view_all), :controller => 'news' %>
</div> </div>
<% end %> <% end %>
<%= call_hook(:view_welcome_index_left, :projects => @projects) %>
</div> </div>
<div class="splitcontentright"> <div class="splitcontentright">
@@ -25,6 +26,7 @@
</ul> </ul>
</div> </div>
<% end %> <% end %>
<%= call_hook(:view_welcome_index_right, :projects => @projects) %>
</div> </div>
<% content_for :header_tags do %> <% content_for :header_tags do %>
+1 -1
View File
@@ -5,7 +5,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style> <style>
body { font:80% Verdana,Tahoma,Arial,sans-serif; } body { font:80% Verdana,Tahoma,Arial,sans-serif; }
h1, h2, h3, h4 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; } h1, h2, h3, h4 { font-family: "Trebuchet MS",Georgia,"Times New Roman",serif; }
ul.toc { padding: 4px; margin-left: 0; } ul.toc { padding: 4px; margin-left: 0; }
ul.toc li { list-style-type:none; } ul.toc li { list-style-type:none; }
ul.toc li.heading2 { margin-left: 1em; } ul.toc li.heading2 { margin-left: 1em; }
+1 -1
View File
@@ -5,7 +5,7 @@
<meta http-equiv="content-type" content="text/html; charset=utf-8" /> <meta http-equiv="content-type" content="text/html; charset=utf-8" />
<style> <style>
body { font:80% Verdana,Tahoma,Arial,sans-serif; } body { font:80% Verdana,Tahoma,Arial,sans-serif; }
h1, h2, h3, h4 { font-family: Trebuchet MS,Georgia,"Times New Roman",serif; } h1, h2, h3, h4 { font-family: "Trebuchet MS",Georgia,"Times New Roman",serif; }
</style> </style>
</head> </head>
<body> <body>
+3 -1
View File
@@ -28,9 +28,10 @@
<%= render(:partial => "wiki/content", :locals => {:content => @content}) %> <%= render(:partial => "wiki/content", :locals => {:content => @content}) %>
<%= link_to_attachments @page.attachments, :delete_url => ((@editable && authorize_for('wiki', 'destroy_attachment')) ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %> <%= link_to_attachments @page %>
<% if @editable && authorize_for('wiki', 'add_attachment') %> <% if @editable && authorize_for('wiki', 'add_attachment') %>
<div id="wiki_add_attachment">
<p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", <p><%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;",
:id => 'attach_files_link' %></p> :id => 'attach_files_link' %></p>
<% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> <% form_tag({ :controller => 'wiki', :action => 'add_attachment', :page => @page.title }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %>
@@ -40,6 +41,7 @@
<%= submit_tag l(:button_add) %> <%= submit_tag l(:button_add) %>
<%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %> <%= link_to l(:button_cancel), {}, :onclick => "Element.hide('add_attachment_form'); Element.show('attach_files_link'); return false;" %>
<% end %> <% end %>
</div>
<% end %> <% end %>
<p class="other-formats"> <p class="other-formats">
+2 -2
View File
@@ -20,11 +20,11 @@
<% unless @pages.empty? %> <% unless @pages.empty? %>
<p class="other-formats"> <p class="other-formats">
<%= l(:label_export_to) %> <%= l(:label_export_to) %>
<span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span> <span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
<span><%= link_to 'HTML', {:action => 'special', :page => 'export'}, :class => 'html' %></span> <span><%= link_to 'HTML', {:action => 'special', :page => 'export'}, :class => 'html' %></span>
</p> </p>
<% end %> <% end %>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key) %> <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>
<% end %> <% end %>
+2 -2
View File
@@ -13,11 +13,11 @@
<% unless @pages.empty? %> <% unless @pages.empty? %>
<p class="other-formats"> <p class="other-formats">
<%= l(:label_export_to) %> <%= l(:label_export_to) %>
<span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span> <span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
<span><%= link_to 'HTML', {:action => 'special', :page => 'export'} %></span> <span><%= link_to 'HTML', {:action => 'special', :page => 'export'} %></span>
</p> </p>
<% end %> <% end %>
<% content_for :header_tags do %> <% content_for :header_tags do %>
<%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key) %> <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %>
<% end %> <% end %>
@@ -0,0 +1,30 @@
# Copyright (c) 2009 Michael Koziarski <michael@koziarski.com>
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
require 'bigdecimal'
alias BigDecimalUnsafe BigDecimal
# This fixes CVE-2009-1904 however it removes legitimate functionality that your
# application may depend on. You are *strongly* advised to upgrade your ruby
# rather than relying on this fix for an extended period of time.
def BigDecimal(initial, digits=0)
if initial.size > 255 || initial =~ /e/i
raise "Invalid big Decimal Value"
end
BigDecimalUnsafe(initial, digits)
end
@@ -2,9 +2,10 @@ class SetTopicAuthorsAsWatchers < ActiveRecord::Migration
def self.up def self.up
# Sets active users who created/replied a topic as watchers of the topic # Sets active users who created/replied a topic as watchers of the topic
# so that the new watch functionality at topic level doesn't affect notifications behaviour # so that the new watch functionality at topic level doesn't affect notifications behaviour
Message.connection.execute("INSERT INTO watchers (watchable_type, watchable_id, user_id)" + Message.connection.execute("INSERT INTO #{Watcher.table_name} (watchable_type, watchable_id, user_id)" +
" SELECT DISTINCT 'Message', COALESCE(messages.parent_id, messages.id), messages.author_id FROM messages, users" + " SELECT DISTINCT 'Message', COALESCE(m.parent_id, m.id), m.author_id" +
" WHERE messages.author_id = users.id AND users.status = 1") " FROM #{Message.table_name} m, #{User.table_name} u" +
" WHERE m.author_id = u.id AND u.status = 1")
end end
def self.down def self.down
+96 -1
View File
@@ -1,10 +1,105 @@
== Redmine changelog == Redmine changelog
Redmine - project management software Redmine - project management software
Copyright (C) 2006-2008 Jean-Philippe Lang Copyright (C) 2006-2009 Jean-Philippe Lang
http://www.redmine.org/ http://www.redmine.org/
== 2009-09-13 v0.8.5
* Incoming mail handler : Allow spaces between keywords and colon
* Do not require a non-word character after a comma in Redmine links
* Include issue hyperlinks in reminder emails
* Prevent nil error when retrieving svn version
* Various plugin hooks added
* Add plugins information to script/about
* Fixed: 500 Internal Server Error is raised if add an empty comment to the news
* Fixed: Atom links for wiki pages are not correct
* Fixed: Atom feeds leak email address
* Fixed: Case sensitivity in Issue filtering
* Fixed: When reading RSS feed, the inline-embedded images are not properly shown
== 2009-05-17 v0.8.4
* Allow textile mailto links
* Fixed: memory consumption when uploading file
* Fixed: Mercurial integration doesn't work if Redmine is installed in folder path containing space
* Fixed: an error is raised when no tab is available on project settings
* Fixed: insert image macro corrupts urls with excalamation marks
* Fixed: error on cross-project gantt PNG export
* Fixed: self and alternate links in atom feeds do not respect Atom specs
* Fixed: accept any svn tunnel scheme in repository URL
* Fixed: issues/show should accept user's rss key
* Fixed: consistency of custom fields display on the issue detail view
* Fixed: wiki comments length validation is missing
* Fixed: weak autologin token generation algorithm causes duplicate tokens
== 2009-04-05 v0.8.3
* Separate project field and subject in cross-project issue view
* Ability to set language for redmine:load_default_data task using REDMINE_LANG environment variable
* Rescue Redmine::DefaultData::DataAlreadyLoaded in redmine:load_default_data task
* CSS classes to highlight own and assigned issues
* Hide "New file" link on wiki pages from printing
* Flush buffer when asking for language in redmine:load_default_data task
* Minimum project identifier length set to 1
* Include headers so that emails don't trigger vacation auto-responders
* Fixed: Time entries csv export links for all projects are malformed
* Fixed: Files without Version aren't visible in the Activity page
* Fixed: Commit logs are centered in the repo browser
* Fixed: News summary field content is not searchable
* Fixed: Journal#save has a wrong signature
* Fixed: Email footer signature convention
* Fixed: Timelog report do not show time for non-versioned issues
== 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
* Issue description is no longer a required field
* Files module: ability to add files without version
* Jump to the current tab when using the project quick-jump combo
* Display a warning if some attachments were not saved
* Import custom fields values from emails on issue creation
* Show view/annotate/download links on entry and annotate views
* Admin Info Screen: Display if plugin assets directory is writable
* Adds a 'Create and continue' button on the new issue form
* IMAP: add options to move received emails
* Do not show Category field when categories are not defined
* Lower the project identifier limit to a minimum of two characters
* Add "closed" html class to closed entries in issue list
* Fixed: broken redirect URL on login failure
* Fixed: Deleted files are shown when using Darcs
* Fixed: Darcs adapter works on Win32 only
* Fixed: syntax highlight doesn't appear in new ticket preview
* Fixed: email notification for changes I make still occurs when running Repository.fetch_changesets
* Fixed: no error is raised when entering invalid hours on the issue update form
* Fixed: Details time log report CSV export doesn't honour date format from settings
* Fixed: invalid css classes on issue details
* Fixed: Trac importer creates duplicate custom values
* Fixed: inline attached image should not match partial filename
== 2008-12-30 v0.8.0 == 2008-12-30 v0.8.0
* Setting added in order to limit the number of diff lines that should be displayed * Setting added in order to limit the number of diff lines that should be displayed

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