Compare commits
354
Commits
nbc
..
0.8-stable
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
90602ac6dc | ||
|
|
8bab5b4730 | ||
|
|
be146d492a | ||
|
|
b49aaccdd6 | ||
|
|
5abb5bf6e1 | ||
|
|
638a9a264a | ||
|
|
051741f05c | ||
|
|
ce41d4f9b0 | ||
|
|
540d204e9a | ||
|
|
2fd4e56ecd | ||
|
|
3d926660ba | ||
|
|
b19ba93966 | ||
|
|
36cc9af651 | ||
|
|
58c24ef2c8 | ||
|
|
ff1b7f4832 | ||
|
|
c12b96a89f | ||
|
|
341a3d1ed6 | ||
|
|
4be1c1ad58 | ||
|
|
eaf0ea0c23 | ||
|
|
d09afa64c8 | ||
|
|
48ee58f6b9 | ||
|
|
3601c13b3b | ||
|
|
88c95e824f | ||
|
|
6ecfcd84b7 | ||
|
|
d884cc3870 | ||
|
|
bdfee87349 | ||
|
|
2ec385858f | ||
|
|
94488269d1 | ||
|
|
3d0fbea9fd | ||
|
|
3d68b60063 | ||
|
|
27b110a61b | ||
|
|
d6394b60a5 | ||
|
|
ffd720eec9 | ||
|
|
50c0cebe96 | ||
|
|
1342228771 | ||
|
|
6872c5e0b9 | ||
|
|
e27460a0a7 | ||
|
|
3f6656a495 | ||
|
|
a3f69e248a | ||
|
|
3022d067ba | ||
|
|
e06987ab52 | ||
|
|
ace65df230 | ||
|
|
c5dadfd322 | ||
|
|
7a59f2df12 | ||
|
|
7b699af837 | ||
|
|
babbe88a86 | ||
|
|
51a9f6a6eb | ||
|
|
16810acf01 | ||
|
|
e28b5e1f08 | ||
|
|
aa38f755c6 | ||
|
|
2679cc2045 | ||
|
|
b6600d5fe9 | ||
|
|
37da5ba187 | ||
|
|
20bdba13cf | ||
|
|
46c0d72782 | ||
|
|
36b5d4f6af | ||
|
|
b366375e7e | ||
|
|
629c106a46 | ||
|
|
f19ae06a72 | ||
|
|
69b99aa518 | ||
|
|
cb5d0c469d | ||
|
|
57d10ed893 | ||
|
|
28e4ff8957 | ||
|
|
3d1bd79ffb | ||
|
|
7f957653ad | ||
|
|
9a9141041e | ||
|
|
bc4249e3d3 | ||
|
|
fae04f3ae1 | ||
|
|
b13ef64794 | ||
|
|
683e1c5d73 | ||
|
|
1c1755d278 | ||
|
|
5e6ff86f47 | ||
|
|
764393aa6a | ||
|
|
3155b8ccad | ||
|
|
567c8ed9b0 | ||
|
|
49b6f9e4dd | ||
|
|
c9d4d3a2be | ||
|
|
31178553f3 | ||
|
|
dea10c54f9 | ||
|
|
6abd32be9e | ||
|
|
56318aab53 | ||
|
|
babb14dd94 | ||
|
|
3b90141543 | ||
|
|
bce764d9bc | ||
|
|
b65d546245 | ||
|
|
9f12151ac0 | ||
|
|
78cac6f02b | ||
|
|
16b85bda32 | ||
|
|
733987fbb6 | ||
|
|
7389b4bed0 | ||
|
|
4570fcb7a2 | ||
|
|
0a709660d2 | ||
|
|
633e026e44 | ||
|
|
618ab6004e | ||
|
|
644f03b834 | ||
|
|
1154141ee7 | ||
|
|
bf42d9b706 | ||
|
|
e2050d61fd | ||
|
|
1dfe63093b | ||
|
|
472ec31662 | ||
|
|
e66945cbd8 | ||
|
|
8a0a25fceb | ||
|
|
cf77c93cb4 | ||
|
|
956437b7fe | ||
|
|
a464d26e73 | ||
|
|
ea77929d62 | ||
|
|
996b2a5c1d | ||
|
|
50794b08a9 | ||
|
|
1b4f0c38ce | ||
|
|
5f9b1b0e0b | ||
|
|
93c04f2666 | ||
|
|
218e1bb267 | ||
|
|
1ce2ed065a | ||
|
|
d3386a5af7 | ||
|
|
5330ca9b8c | ||
|
|
84247e7272 | ||
|
|
e7b6a56a97 | ||
|
|
9572699301 | ||
|
|
84e70634fb | ||
|
|
94899e0339 | ||
|
|
abacc2754e | ||
|
|
2fa8030afc | ||
|
|
0b2299c7d1 | ||
|
|
5f3f2e756b | ||
|
|
dfc7a94578 | ||
|
|
0399b85ab6 | ||
|
|
9e5edfb728 | ||
|
|
b8b473244c | ||
|
|
6e777b7453 | ||
|
|
fce4615f10 | ||
|
|
b5fcea9e74 | ||
|
|
5014b23c2a | ||
|
|
a6b6dc60f4 | ||
|
|
9b1efcfaab | ||
|
|
546b98a118 | ||
|
|
7a441c1bc4 | ||
|
|
c54f15e35f | ||
|
|
db37e578f2 | ||
|
|
9e1192a54d | ||
|
|
06266c8fec | ||
|
|
af7e586b06 | ||
|
|
0b94f4afa9 | ||
|
|
5a51412e6a | ||
|
|
752d574b49 | ||
|
|
a303b5e2d5 | ||
|
|
e61916ea91 | ||
|
|
86504acb4c | ||
|
|
3fdc273252 | ||
|
|
9882217847 | ||
|
|
5362a85f2b | ||
|
|
f9ce4ff559 | ||
|
|
fefc6e6bec | ||
|
|
97252c26ee | ||
|
|
94b5bbcb5d | ||
|
|
9c09fd20fb | ||
|
|
79b1347ba5 | ||
|
|
0cef17ce44 | ||
|
|
d1b1f5977a | ||
|
|
33274b8d48 | ||
|
|
7c1d8ac00b | ||
|
|
243027e63a | ||
|
|
9d810f0059 | ||
|
|
eaedf9ed52 | ||
|
|
c894f74c5e | ||
|
|
8d8315d8f6 | ||
|
|
7f63f9a931 | ||
|
|
27af58ef1a | ||
|
|
fb4bab748f | ||
|
|
d771847078 | ||
|
|
3f4defe482 | ||
|
|
737bbb3d3d | ||
|
|
7a05f8ed66 | ||
|
|
cbacc71dff | ||
|
|
ad97165f1b | ||
|
|
8be1597ad0 | ||
|
|
1169ff05af | ||
|
|
876a9b6ffb | ||
|
|
d545ca7360 | ||
|
|
1802fa9348 | ||
|
|
29bad1dc95 | ||
|
|
6a8be88ad6 | ||
|
|
e8d0c26e43 | ||
|
|
4ed95ffff6 | ||
|
|
6f68a36679 | ||
|
|
79c33bbc83 | ||
|
|
f6b2be81b9 | ||
|
|
486ecc6661 | ||
|
|
5166213fd3 | ||
|
|
57a4ee318a | ||
|
|
d63746ab3e | ||
|
|
7619c286cc | ||
|
|
6157d20ec0 | ||
|
|
858eba2f1c | ||
|
|
365d92ebf4 | ||
|
|
11b9ceb054 | ||
|
|
9352bb527b | ||
|
|
47475acdaf | ||
|
|
9ae6e60c26 | ||
|
|
077723c90a | ||
|
|
81eee10d5b | ||
|
|
63c72fe87f | ||
|
|
006337fb0e | ||
|
|
4581baa5c0 | ||
|
|
203cf6333e | ||
|
|
b7c1a5c0d5 | ||
|
|
0ecca9d8f1 | ||
|
|
c58298835d | ||
|
|
42452a535f | ||
|
|
d32b9b92cf | ||
|
|
de31cd9ef6 | ||
|
|
a9295a7740 | ||
|
|
8b3a8ac1b4 | ||
|
|
b1cb9cd3bd | ||
|
|
76d33e1fb7 | ||
|
|
0dc6a41832 | ||
|
|
34b86628a0 | ||
|
|
66b9a76c7e | ||
|
|
bbc43e71ee | ||
|
|
ba20a67873 | ||
|
|
048fa5bd77 | ||
|
|
3bc2a5cf2f | ||
|
|
41dba2db86 | ||
|
|
e85a9f8609 | ||
|
|
b84dd8ec83 | ||
|
|
01fd8e685b | ||
|
|
1a6595aa17 | ||
|
|
9373f429d0 | ||
|
|
b3442a7d39 | ||
|
|
ed314caf7d | ||
|
|
1399f3dd12 | ||
|
|
7c99f8ad11 | ||
|
|
67159c12c5 | ||
|
|
0f1787ea0d | ||
|
|
6cd4f0c07e | ||
|
|
d143019dbb | ||
|
|
a3b9a5aa5f | ||
|
|
9b624fd1d6 | ||
|
|
8236563d6b | ||
|
|
5f9f6ea2e1 | ||
|
|
738fc579f0 | ||
|
|
0316fde06b | ||
|
|
bcde2f4dce | ||
|
|
48ae6f38e1 | ||
|
|
16eda4c5c9 | ||
|
|
b4101c8b65 | ||
|
|
d967507dcb | ||
|
|
d1b5bc1e82 | ||
|
|
6c54b0ba3b | ||
|
|
bdbc7b337f | ||
|
|
ff449b197f | ||
|
|
a0c29d8f99 | ||
|
|
58fbf5e66f | ||
|
|
ccbe48d779 | ||
|
|
64e67f754d | ||
|
|
6810972762 | ||
|
|
e160a3eec1 | ||
|
|
f16aae74dc | ||
|
|
bc77cc2c5c | ||
|
|
a4b07a36ed | ||
|
|
1894bef48a | ||
|
|
2ed9aa13f3 | ||
|
|
52e422da61 | ||
|
|
8b0016d71b | ||
|
|
df761e01fa | ||
|
|
07962e2840 | ||
|
|
7fe7677cde | ||
|
|
c4419e268f | ||
|
|
cf1ad65cd2 | ||
|
|
193ed689fb | ||
|
|
f2f54a711d | ||
|
|
0092a54e3b | ||
|
|
1ffa468240 | ||
|
|
ae0ed7fd05 | ||
|
|
b0e62e37ae | ||
|
|
3544d6398a | ||
|
|
5083e92772 | ||
|
|
a37af7a226 | ||
|
|
85711f1d54 | ||
|
|
050d0d046a | ||
|
|
925ef8f4f0 | ||
|
|
ad06bec6b6 | ||
|
|
433f2a043e | ||
|
|
394fc9c109 | ||
|
|
21979cf68a | ||
|
|
0177f732a2 | ||
|
|
a3cf5dcded | ||
|
|
8bc89b6e73 | ||
|
|
2e7e26fbb4 | ||
|
|
9131cdf6b9 | ||
|
|
fbf2646426 | ||
|
|
edf6757a75 | ||
|
|
8cb75be0db | ||
|
|
b09a18972d | ||
|
|
8a356baf3e | ||
|
|
e1c4659752 | ||
|
|
72c9884dfc | ||
|
|
7afdb01f00 | ||
|
|
1d542a5113 | ||
|
|
199428804f | ||
|
|
6854827f1a | ||
|
|
5452fd2f5a | ||
|
|
701e00d865 | ||
|
|
4e36bd2ce1 | ||
|
|
124ea898d5 | ||
|
|
07b69fd7fc | ||
|
|
952ff4184e | ||
|
|
5c449f844e | ||
|
|
16e09bfd77 | ||
|
|
9e7bce6a94 | ||
|
|
710ac5344d | ||
|
|
36aeeb99d9 | ||
|
|
713ce06e40 | ||
|
|
fcbd2b5228 | ||
|
|
14b4afeec9 | ||
|
|
3520961eae | ||
|
|
0961cdab31 | ||
|
|
a987649b1a | ||
|
|
9afaf26d66 | ||
|
|
a07a6d4aa4 | ||
|
|
25ed19cb35 | ||
|
|
1f862dbadb | ||
|
|
3ef92341fd | ||
|
|
225b6f4dc9 | ||
|
|
094520ab20 | ||
|
|
90dc93b81c | ||
|
|
323a26030b | ||
|
|
653d2aacbb | ||
|
|
f6b05ea3fb | ||
|
|
3041041a62 | ||
|
|
691b09fd72 | ||
|
|
f30a369d35 | ||
|
|
487ba400fc | ||
|
|
2e0cd9f196 | ||
|
|
59c961425e | ||
|
|
570d7e494e | ||
|
|
1f1fd9e034 | ||
|
|
35bb9307dc | ||
|
|
47679629f4 | ||
|
|
06f4b371ee | ||
|
|
c3040104ff | ||
|
|
455abea320 | ||
|
|
cc643ce932 | ||
|
|
6ef6459630 | ||
|
|
827e14eafe | ||
|
|
8fac9233de | ||
|
|
7385722441 | ||
|
|
b73141a153 | ||
|
|
8d6b32645c | ||
|
|
a592d6c40d | ||
|
|
fb151463eb | ||
|
|
586f4e3831 | ||
|
|
2986afc05e | ||
|
|
a8e3ddf382 | ||
|
|
de7d367820 |
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 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
|
||||||
@@ -15,19 +15,19 @@
|
|||||||
# 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.
|
||||||
|
|
||||||
module Redmine
|
class AWSProjectWithRepository < ActionWebService::Struct
|
||||||
module Views
|
member :id, :int
|
||||||
class OtherFormatsBuilder
|
member :identifier, :string
|
||||||
def initialize(view)
|
member :name, :string
|
||||||
@view = view
|
member :is_public, :bool
|
||||||
end
|
member :repository, Repository
|
||||||
|
end
|
||||||
def link_to(name, options={})
|
|
||||||
url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {})
|
class SysApi < ActionWebService::API::Base
|
||||||
caption = options.delete(:caption) || name
|
api_method :projects_with_repository_enabled,
|
||||||
html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options)
|
:expects => [],
|
||||||
@view.content_tag('span', @view.link_to(caption, url, html_options))
|
:returns => [[AWSProjectWithRepository]]
|
||||||
end
|
api_method :repository_created,
|
||||||
end
|
:expects => [:string, :string, :string],
|
||||||
end
|
:returns => [:int]
|
||||||
end
|
end
|
||||||
@@ -35,6 +35,10 @@ class AccountController < ApplicationController
|
|||||||
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
|
events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10)
|
||||||
@events_by_day = events.group_by(&:event_date)
|
@events_by_day = events.group_by(&:event_date)
|
||||||
|
|
||||||
|
if @user != User.current && !User.current.admin? && @memberships.empty? && events.empty?
|
||||||
|
render_404 and return
|
||||||
|
end
|
||||||
|
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
render_404
|
render_404
|
||||||
end
|
end
|
||||||
@@ -46,10 +50,25 @@ class AccountController < ApplicationController
|
|||||||
self.logged_user = nil
|
self.logged_user = nil
|
||||||
else
|
else
|
||||||
# Authenticate user
|
# Authenticate user
|
||||||
if Setting.openid? && using_open_id?
|
user = User.try_to_login(params[:username], params[:password])
|
||||||
open_id_authenticate(params[:openid_url])
|
if user.nil?
|
||||||
|
# Invalid credentials
|
||||||
|
flash.now[:error] = l(:notice_account_invalid_creditentials)
|
||||||
|
elsif user.new_record?
|
||||||
|
# Onthefly creation failed, display the registration form to fill/fix attributes
|
||||||
|
@user = user
|
||||||
|
session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id }
|
||||||
|
render :action => 'register'
|
||||||
else
|
else
|
||||||
password_authentication
|
# Valid user
|
||||||
|
self.logged_user = user
|
||||||
|
# generate a key and set cookie if autologin
|
||||||
|
if params[:autologin] && Setting.autologin?
|
||||||
|
token = Token.create(:user => user, :action => 'autologin')
|
||||||
|
cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
|
||||||
|
end
|
||||||
|
call_hook(:controller_account_success_authentication_after, {:user => user })
|
||||||
|
redirect_back_or_default :controller => 'my', :action => 'page'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -122,14 +141,31 @@ class AccountController < ApplicationController
|
|||||||
else
|
else
|
||||||
@user.login = params[:user][:login]
|
@user.login = params[:user][:login]
|
||||||
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
|
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
|
||||||
|
|
||||||
case Setting.self_registration
|
case Setting.self_registration
|
||||||
when '1'
|
when '1'
|
||||||
register_by_email_activation(@user)
|
# Email activation
|
||||||
|
token = Token.new(:user => @user, :action => "register")
|
||||||
|
if @user.save and token.save
|
||||||
|
Mailer.deliver_register(token)
|
||||||
|
flash[:notice] = l(:notice_account_register_done)
|
||||||
|
redirect_to :action => 'login'
|
||||||
|
end
|
||||||
when '3'
|
when '3'
|
||||||
register_automatically(@user)
|
# Automatic activation
|
||||||
|
@user.status = User::STATUS_ACTIVE
|
||||||
|
if @user.save
|
||||||
|
self.logged_user = @user
|
||||||
|
flash[:notice] = l(:notice_account_activated)
|
||||||
|
redirect_to :controller => 'my', :action => 'account'
|
||||||
|
end
|
||||||
else
|
else
|
||||||
register_manually_by_administrator(@user)
|
# Manual activation by the administrator
|
||||||
|
if @user.save
|
||||||
|
# Sends an email to the administrators
|
||||||
|
Mailer.deliver_account_activation_request(@user)
|
||||||
|
flash[:notice] = l(:notice_account_pending)
|
||||||
|
redirect_to :action => 'login'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -152,127 +188,12 @@ class AccountController < ApplicationController
|
|||||||
|
|
||||||
private
|
private
|
||||||
def logged_user=(user)
|
def logged_user=(user)
|
||||||
|
reset_session
|
||||||
if user && user.is_a?(User)
|
if user && user.is_a?(User)
|
||||||
User.current = user
|
User.current = user
|
||||||
session[:user_id] = user.id
|
session[:user_id] = user.id
|
||||||
else
|
else
|
||||||
User.current = User.anonymous
|
User.current = User.anonymous
|
||||||
session[:user_id] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def password_authentication
|
|
||||||
user = User.try_to_login(params[:username], params[:password])
|
|
||||||
if user.nil?
|
|
||||||
# Invalid credentials
|
|
||||||
flash.now[:error] = l(:notice_account_invalid_creditentials)
|
|
||||||
elsif user.new_record?
|
|
||||||
# Onthefly creation failed, display the registration form to fill/fix attributes
|
|
||||||
@user = user
|
|
||||||
session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id }
|
|
||||||
render :action => 'register'
|
|
||||||
else
|
|
||||||
# Valid user
|
|
||||||
successful_authentication(user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
def open_id_authenticate(openid_url)
|
|
||||||
authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration|
|
|
||||||
if result.successful?
|
|
||||||
user = User.find_or_initialize_by_identity_url(identity_url)
|
|
||||||
if user.new_record?
|
|
||||||
# Self-registration off
|
|
||||||
redirect_to(home_url) && return unless Setting.self_registration?
|
|
||||||
|
|
||||||
# Create on the fly
|
|
||||||
user.login = registration['nickname'] unless registration['nickname'].nil?
|
|
||||||
user.mail = registration['email'] unless registration['email'].nil?
|
|
||||||
user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil?
|
|
||||||
user.random_password
|
|
||||||
user.status = User::STATUS_REGISTERED
|
|
||||||
|
|
||||||
case Setting.self_registration
|
|
||||||
when '1'
|
|
||||||
register_by_email_activation(user) do
|
|
||||||
onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url })
|
|
||||||
end
|
|
||||||
when '3'
|
|
||||||
register_automatically(user) do
|
|
||||||
onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url })
|
|
||||||
end
|
|
||||||
else
|
|
||||||
register_manually_by_administrator(user) do
|
|
||||||
onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# Existing record
|
|
||||||
successful_authentication(user)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def successful_authentication(user)
|
|
||||||
# Valid user
|
|
||||||
self.logged_user = user
|
|
||||||
# generate a key and set cookie if autologin
|
|
||||||
if params[:autologin] && Setting.autologin?
|
|
||||||
token = Token.create(:user => user, :action => 'autologin')
|
|
||||||
cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now }
|
|
||||||
end
|
|
||||||
redirect_back_or_default :controller => 'my', :action => 'page'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Onthefly creation failed, display the registration form to fill/fix attributes
|
|
||||||
def onthefly_creation_failed(user, auth_source_options = { })
|
|
||||||
@user = user
|
|
||||||
session[:auth_source_registration] = auth_source_options unless auth_source_options.empty?
|
|
||||||
render :action => 'register'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Register a user for email activation.
|
|
||||||
#
|
|
||||||
# Pass a block for behavior when a user fails to save
|
|
||||||
def register_by_email_activation(user, &block)
|
|
||||||
token = Token.new(:user => user, :action => "register")
|
|
||||||
if user.save and token.save
|
|
||||||
Mailer.deliver_register(token)
|
|
||||||
flash[:notice] = l(:notice_account_register_done)
|
|
||||||
redirect_to :action => 'login'
|
|
||||||
else
|
|
||||||
yield if block_given?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Automatically register a user
|
|
||||||
#
|
|
||||||
# Pass a block for behavior when a user fails to save
|
|
||||||
def register_automatically(user, &block)
|
|
||||||
# Automatic activation
|
|
||||||
user.status = User::STATUS_ACTIVE
|
|
||||||
if user.save
|
|
||||||
self.logged_user = user
|
|
||||||
flash[:notice] = l(:notice_account_activated)
|
|
||||||
redirect_to :controller => 'my', :action => 'account'
|
|
||||||
else
|
|
||||||
yield if block_given?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Manual activation by the administrator
|
|
||||||
#
|
|
||||||
# Pass a block for behavior when a user fails to save
|
|
||||||
def register_manually_by_administrator(user, &block)
|
|
||||||
if user.save
|
|
||||||
# Sends an email to the administrators
|
|
||||||
Mailer.deliver_account_activation_request(user)
|
|
||||||
flash[:notice] = l(:notice_account_pending)
|
|
||||||
redirect_to :action => 'login'
|
|
||||||
else
|
|
||||||
yield if block_given?
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ class AdminController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def projects
|
def projects
|
||||||
|
sort_init 'name', 'asc'
|
||||||
|
sort_update %w(name is_public created_on)
|
||||||
|
|
||||||
@status = params[:status] ? params[:status].to_i : 1
|
@status = params[:status] ? params[:status].to_i : 1
|
||||||
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status])
|
||||||
|
|
||||||
@@ -34,8 +37,14 @@ class AdminController < ApplicationController
|
|||||||
c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name]
|
c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name]
|
||||||
end
|
end
|
||||||
|
|
||||||
@projects = Project.find :all, :order => 'lft',
|
@project_count = Project.count(:conditions => c.conditions)
|
||||||
:conditions => c.conditions
|
@project_pages = Paginator.new self, @project_count,
|
||||||
|
per_page_option,
|
||||||
|
params['page']
|
||||||
|
@projects = Project.find :all, :order => sort_clause,
|
||||||
|
:conditions => c.conditions,
|
||||||
|
:limit => @project_pages.items_per_page,
|
||||||
|
:offset => @project_pages.current.offset
|
||||||
|
|
||||||
render :action => "projects", :layout => false if request.xhr?
|
render :action => "projects", :layout => false if request.xhr?
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -19,10 +19,17 @@ require 'uri'
|
|||||||
require 'cgi'
|
require 'cgi'
|
||||||
|
|
||||||
class ApplicationController < ActionController::Base
|
class ApplicationController < ActionController::Base
|
||||||
|
class MissingSessionSecret < Exception ; end
|
||||||
layout 'base'
|
layout 'base'
|
||||||
|
|
||||||
before_filter :user_setup, :check_if_login_required, :set_localization
|
before_filter :user_setup, :check_if_login_required, :set_localization
|
||||||
filter_parameter_logging :password
|
filter_parameter_logging :password
|
||||||
|
|
||||||
|
if session.first[:secret].blank?
|
||||||
|
raise MissingSessionSecret, "Missing session secret. Please run 'rake config/initializers/session_store.rb' to generate one"
|
||||||
|
else
|
||||||
|
protect_from_forgery :secret => session.first[:secret]
|
||||||
|
end
|
||||||
|
|
||||||
include Redmine::MenuManager::MenuController
|
include Redmine::MenuManager::MenuController
|
||||||
helper Redmine::MenuManager::MenuHelper
|
helper Redmine::MenuManager::MenuHelper
|
||||||
@@ -82,7 +89,13 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
def require_login
|
def require_login
|
||||||
if !User.current.logged?
|
if !User.current.logged?
|
||||||
redirect_to :controller => "account", :action => "login", :back_url => url_for(params)
|
# Extract only the basic url parameters on non-GET requests
|
||||||
|
if request.get?
|
||||||
|
url = url_for(params)
|
||||||
|
else
|
||||||
|
url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id])
|
||||||
|
end
|
||||||
|
redirect_to :controller => "account", :action => "login", :back_url => url
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
true
|
true
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ class AttachmentsController < ApplicationController
|
|||||||
elsif @attachment.is_text?
|
elsif @attachment.is_text?
|
||||||
@content = File.new(@attachment.diskfile, "rb").read
|
@content = File.new(@attachment.diskfile, "rb").read
|
||||||
render :action => 'file'
|
render :action => 'file'
|
||||||
else
|
elsif
|
||||||
download
|
download
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
# Copyright (C) 2006 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
|
||||||
@@ -19,22 +19,35 @@ class CustomFieldsController < ApplicationController
|
|||||||
before_filter :require_admin
|
before_filter :require_admin
|
||||||
|
|
||||||
def index
|
def index
|
||||||
|
list
|
||||||
|
render :action => 'list' unless request.xhr?
|
||||||
|
end
|
||||||
|
|
||||||
|
def list
|
||||||
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
|
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name }
|
||||||
@tab = params[:tab] || 'IssueCustomField'
|
@tab = params[:tab] || 'IssueCustomField'
|
||||||
|
render :action => "list", :layout => false if request.xhr?
|
||||||
end
|
end
|
||||||
|
|
||||||
def new
|
def new
|
||||||
@custom_field = begin
|
case params[:type]
|
||||||
if params[:type].to_s.match(/.+CustomField$/)
|
when "IssueCustomField"
|
||||||
params[:type].to_s.constantize.new(params[:custom_field])
|
@custom_field = IssueCustomField.new(params[:custom_field])
|
||||||
end
|
@custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids]
|
||||||
rescue
|
when "UserCustomField"
|
||||||
end
|
@custom_field = UserCustomField.new(params[:custom_field])
|
||||||
redirect_to(:action => 'index') and return unless @custom_field.is_a?(CustomField)
|
when "ProjectCustomField"
|
||||||
|
@custom_field = ProjectCustomField.new(params[:custom_field])
|
||||||
|
when "TimeEntryCustomField"
|
||||||
|
@custom_field = TimeEntryCustomField.new(params[:custom_field])
|
||||||
|
else
|
||||||
|
redirect_to :action => 'list'
|
||||||
|
return
|
||||||
|
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)
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field)
|
||||||
|
redirect_to :action => 'list', :tab => @custom_field.class.name
|
||||||
end
|
end
|
||||||
@trackers = Tracker.find(:all, :order => 'position')
|
@trackers = Tracker.find(:all, :order => 'position')
|
||||||
end
|
end
|
||||||
@@ -42,8 +55,12 @@ class CustomFieldsController < ApplicationController
|
|||||||
def edit
|
def edit
|
||||||
@custom_field = CustomField.find(params[:id])
|
@custom_field = CustomField.find(params[:id])
|
||||||
if request.post? and @custom_field.update_attributes(params[:custom_field])
|
if request.post? and @custom_field.update_attributes(params[:custom_field])
|
||||||
|
if @custom_field.is_a? IssueCustomField
|
||||||
|
@custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : []
|
||||||
|
end
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field)
|
||||||
|
redirect_to :action => 'list', :tab => @custom_field.class.name
|
||||||
end
|
end
|
||||||
@trackers = Tracker.find(:all, :order => 'position')
|
@trackers = Tracker.find(:all, :order => 'position')
|
||||||
end
|
end
|
||||||
@@ -60,14 +77,14 @@ class CustomFieldsController < ApplicationController
|
|||||||
when 'lowest'
|
when 'lowest'
|
||||||
@custom_field.move_to_bottom
|
@custom_field.move_to_bottom
|
||||||
end if params[:position]
|
end if params[:position]
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
redirect_to :action => 'list', :tab => @custom_field.class.name
|
||||||
end
|
end
|
||||||
|
|
||||||
def destroy
|
def destroy
|
||||||
@custom_field = CustomField.find(params[:id]).destroy
|
@custom_field = CustomField.find(params[:id]).destroy
|
||||||
redirect_to :action => 'index', :tab => @custom_field.class.name
|
redirect_to :action => 'list', :tab => @custom_field.class.name
|
||||||
rescue
|
rescue
|
||||||
flash[:error] = "Unable to delete custom field"
|
flash[:error] = "Unable to delete custom field"
|
||||||
redirect_to :action => 'index'
|
redirect_to :action => 'list'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -21,9 +21,6 @@ class IssueRelationsController < ApplicationController
|
|||||||
def new
|
def new
|
||||||
@relation = IssueRelation.new(params[:relation])
|
@relation = IssueRelation.new(params[:relation])
|
||||||
@relation.issue_from = @issue
|
@relation.issue_from = @issue
|
||||||
if params[:relation] && !params[:relation][:issue_to_id].blank?
|
|
||||||
@relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id])
|
|
||||||
end
|
|
||||||
@relation.save if request.post?
|
@relation.save if request.post?
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue }
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class IssuesController < ApplicationController
|
|||||||
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
|
||||||
@@ -43,6 +43,10 @@ class IssuesController < ApplicationController
|
|||||||
helper :timelog
|
helper :timelog
|
||||||
include Redmine::Export::PDF
|
include Redmine::Export::PDF
|
||||||
|
|
||||||
|
verify :method => :post,
|
||||||
|
:only => :destroy,
|
||||||
|
:render => { :nothing => true, :status => :method_not_allowed }
|
||||||
|
|
||||||
def index
|
def index
|
||||||
retrieve_query
|
retrieve_query
|
||||||
sort_init 'id', 'desc'
|
sort_init 'id', 'desc'
|
||||||
@@ -232,7 +236,6 @@ class IssuesController < ApplicationController
|
|||||||
assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id])
|
assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id])
|
||||||
category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id])
|
category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id])
|
||||||
fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.versions.find_by_id(params[:fixed_version_id])
|
fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.versions.find_by_id(params[:fixed_version_id])
|
||||||
custom_field_values = params[:custom_field_values] ? params[:custom_field_values].reject {|k,v| v.blank?} : nil
|
|
||||||
|
|
||||||
unsaved_issue_ids = []
|
unsaved_issue_ids = []
|
||||||
@issues.each do |issue|
|
@issues.each do |issue|
|
||||||
@@ -244,7 +247,6 @@ class IssuesController < ApplicationController
|
|||||||
issue.start_date = params[:start_date] unless params[:start_date].blank?
|
issue.start_date = params[:start_date] unless params[:start_date].blank?
|
||||||
issue.due_date = params[:due_date] unless params[:due_date].blank?
|
issue.due_date = params[:due_date] unless params[:due_date].blank?
|
||||||
issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank?
|
issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank?
|
||||||
issue.custom_field_values = custom_field_values if custom_field_values && !custom_field_values.empty?
|
|
||||||
call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
|
call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue })
|
||||||
# Don't save any change to the issue if the user is not authorized to apply the requested status
|
# Don't save any change to the issue if the user is not authorized to apply the requested status
|
||||||
if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save
|
if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save
|
||||||
@@ -266,7 +268,6 @@ class IssuesController < ApplicationController
|
|||||||
# Find potential statuses the user could be allowed to switch issues to
|
# Find potential statuses the user could be allowed to switch issues to
|
||||||
@available_statuses = Workflow.find(:all, :include => :new_status,
|
@available_statuses = Workflow.find(:all, :include => :new_status,
|
||||||
:conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq.sort
|
:conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq.sort
|
||||||
@custom_fields = @project.issue_custom_fields.select {|f| f.field_format == 'list'}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def move
|
def move
|
||||||
@@ -274,7 +275,7 @@ class IssuesController < ApplicationController
|
|||||||
# find projects to which the user is allowed to move the issue
|
# find projects to which the user is allowed to move the issue
|
||||||
if User.current.admin?
|
if User.current.admin?
|
||||||
# admin is allowed to move issues to any active (visible) project
|
# admin is allowed to move issues to any active (visible) project
|
||||||
@allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current))
|
@allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current), :order => 'name')
|
||||||
else
|
else
|
||||||
User.current.memberships.each {|m| @allowed_projects << m.project if m.role.allowed_to?(:move_issues)}
|
User.current.memberships.each {|m| @allowed_projects << m.project if m.role.allowed_to?(:move_issues)}
|
||||||
end
|
end
|
||||||
@@ -286,7 +287,7 @@ class IssuesController < ApplicationController
|
|||||||
unsaved_issue_ids = []
|
unsaved_issue_ids = []
|
||||||
@issues.each do |issue|
|
@issues.each do |issue|
|
||||||
issue.init_journal(User.current)
|
issue.init_journal(User.current)
|
||||||
unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker, params[:copy_options])
|
unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker)
|
||||||
end
|
end
|
||||||
if unsaved_issue_ids.empty?
|
if unsaved_issue_ids.empty?
|
||||||
flash[:notice] = l(:notice_successful_update) unless @issues.empty?
|
flash[:notice] = l(:notice_successful_update) unless @issues.empty?
|
||||||
@@ -348,10 +349,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.nil? ? '' : "#{@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(gantt_to_pdf(@gantt, @project), :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
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ class MyController < ApplicationController
|
|||||||
before_filter :require_login
|
before_filter :require_login
|
||||||
|
|
||||||
helper :issues
|
helper :issues
|
||||||
helper :custom_fields
|
|
||||||
|
|
||||||
BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues,
|
BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues,
|
||||||
'issuesreportedbyme' => :label_reported_issues,
|
'issuesreportedbyme' => :label_reported_issues,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -29,12 +29,6 @@ class ProjectsController < ApplicationController
|
|||||||
before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ]
|
before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ]
|
||||||
accept_key_auth :activity
|
accept_key_auth :activity
|
||||||
|
|
||||||
after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller|
|
|
||||||
if controller.request.post?
|
|
||||||
controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
helper :sort
|
helper :sort
|
||||||
include SortHelper
|
include SortHelper
|
||||||
helper :custom_fields
|
helper :custom_fields
|
||||||
@@ -49,14 +43,17 @@ class ProjectsController < ApplicationController
|
|||||||
|
|
||||||
# Lists visible projects
|
# Lists visible projects
|
||||||
def index
|
def index
|
||||||
|
projects = Project.find :all,
|
||||||
|
:conditions => Project.visible_by(User.current),
|
||||||
|
:include => :parent
|
||||||
respond_to do |format|
|
respond_to do |format|
|
||||||
format.html {
|
format.html {
|
||||||
@projects = Project.visible.find(:all, :order => 'lft')
|
@project_tree = projects.group_by {|p| p.parent || p}
|
||||||
|
@project_tree.keys.each {|p| @project_tree[p] -= [p]}
|
||||||
}
|
}
|
||||||
format.atom {
|
format.atom {
|
||||||
projects = Project.visible.find(:all, :order => 'created_on DESC',
|
render_feed(projects.sort_by(&:created_on).reverse.slice(0, Setting.feeds_limit.to_i),
|
||||||
:limit => Setting.feeds_limit.to_i)
|
:title => "#{Setting.app_title}: #{l(:label_project_latest)}")
|
||||||
render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}")
|
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -65,6 +62,9 @@ class ProjectsController < ApplicationController
|
|||||||
def add
|
def add
|
||||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||||
@trackers = Tracker.all
|
@trackers = Tracker.all
|
||||||
|
@root_projects = Project.find(:all,
|
||||||
|
:conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
|
||||||
|
:order => 'name')
|
||||||
@project = Project.new(params[:project])
|
@project = Project.new(params[:project])
|
||||||
if request.get?
|
if request.get?
|
||||||
@project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
|
@project.identifier = Project.next_identifier if Setting.sequential_project_identifiers?
|
||||||
@@ -74,7 +74,6 @@ class ProjectsController < ApplicationController
|
|||||||
else
|
else
|
||||||
@project.enabled_module_names = params[:enabled_modules]
|
@project.enabled_module_names = params[:enabled_modules]
|
||||||
if @project.save
|
if @project.save
|
||||||
@project.set_parent!(params[:project]['parent_id']) if User.current.admin? && params[:project].has_key?('parent_id')
|
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :controller => 'admin', :action => 'projects'
|
redirect_to :controller => 'admin', :action => 'projects'
|
||||||
end
|
end
|
||||||
@@ -89,20 +88,19 @@ class ProjectsController < ApplicationController
|
|||||||
end
|
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.visible
|
@subprojects = @project.children.find(:all, :conditions => Project.visible_by(User.current))
|
||||||
@ancestors = @project.ancestors.visible
|
|
||||||
@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")
|
||||||
@trackers = @project.rolled_up_trackers
|
@trackers = @project.rolled_up_trackers
|
||||||
|
|
||||||
cond = @project.project_condition(Setting.display_subprojects_issues?)
|
cond = @project.project_condition(Setting.display_subprojects_issues?)
|
||||||
|
Issue.visible_by(User.current) do
|
||||||
@open_issues_by_tracker = Issue.visible.count(:group => :tracker,
|
@open_issues_by_tracker = Issue.count(:group => :tracker,
|
||||||
:include => [:project, :status, :tracker],
|
:include => [:project, :status, :tracker],
|
||||||
:conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
|
:conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false])
|
||||||
@total_issues_by_tracker = Issue.visible.count(:group => :tracker,
|
@total_issues_by_tracker = Issue.count(:group => :tracker,
|
||||||
:include => [:project, :status, :tracker],
|
:include => [:project, :status, :tracker],
|
||||||
:conditions => cond)
|
:conditions => cond)
|
||||||
|
end
|
||||||
TimeEntry.visible_by(User.current) do
|
TimeEntry.visible_by(User.current) do
|
||||||
@total_hours = TimeEntry.sum(:hours,
|
@total_hours = TimeEntry.sum(:hours,
|
||||||
:include => :project,
|
:include => :project,
|
||||||
@@ -112,6 +110,9 @@ class ProjectsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def settings
|
def settings
|
||||||
|
@root_projects = Project.find(:all,
|
||||||
|
:conditions => ["parent_id IS NULL AND status = #{Project::STATUS_ACTIVE} AND id <> ?", @project.id],
|
||||||
|
:order => 'name')
|
||||||
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
@issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position")
|
||||||
@issue_category ||= IssueCategory.new
|
@issue_category ||= IssueCategory.new
|
||||||
@member ||= @project.members.new
|
@member ||= @project.members.new
|
||||||
@@ -125,7 +126,6 @@ class ProjectsController < ApplicationController
|
|||||||
if request.post?
|
if request.post?
|
||||||
@project.attributes = params[:project]
|
@project.attributes = params[:project]
|
||||||
if @project.save
|
if @project.save
|
||||||
@project.set_parent!(params[:project]['parent_id']) if User.current.admin? && params[:project].has_key?('parent_id')
|
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'settings', :id => @project
|
redirect_to :action => 'settings', :id => @project
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class ReportsController < ApplicationController
|
|||||||
render :template => "reports/issue_report_details"
|
render :template => "reports/issue_report_details"
|
||||||
when "subproject"
|
when "subproject"
|
||||||
@field = "project_id"
|
@field = "project_id"
|
||||||
@rows = @project.descendants.active
|
@rows = @project.active_children
|
||||||
@data = issues_by_subproject
|
@data = issues_by_subproject
|
||||||
@report_title = l(:field_subproject)
|
@report_title = l(:field_subproject)
|
||||||
render :template => "reports/issue_report_details"
|
render :template => "reports/issue_report_details"
|
||||||
@@ -72,7 +72,7 @@ class ReportsController < ApplicationController
|
|||||||
@categories = @project.issue_categories
|
@categories = @project.issue_categories
|
||||||
@assignees = @project.members.collect { |m| m.user }
|
@assignees = @project.members.collect { |m| m.user }
|
||||||
@authors = @project.members.collect { |m| m.user }
|
@authors = @project.members.collect { |m| m.user }
|
||||||
@subprojects = @project.descendants.active
|
@subprojects = @project.active_children
|
||||||
issues_by_tracker
|
issues_by_tracker
|
||||||
issues_by_version
|
issues_by_version
|
||||||
issues_by_priority
|
issues_by_priority
|
||||||
@@ -229,8 +229,8 @@ private
|
|||||||
#{Issue.table_name} i, #{IssueStatus.table_name} s
|
#{Issue.table_name} i, #{IssueStatus.table_name} s
|
||||||
where
|
where
|
||||||
i.status_id=s.id
|
i.status_id=s.id
|
||||||
and i.project_id IN (#{@project.descendants.active.collect{|p| p.id}.join(',')})
|
and i.project_id IN (#{@project.active_children.collect{|p| p.id}.join(',')})
|
||||||
group by s.id, s.is_closed, i.project_id") if @project.descendants.active.any?
|
group by s.id, s.is_closed, i.project_id") if @project.active_children.any?
|
||||||
@issues_by_subproject ||= []
|
@issues_by_subproject ||= []
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class RepositoriesController < ApplicationController
|
|||||||
def changes
|
def changes
|
||||||
@entry = @repository.entry(@path, @rev)
|
@entry = @repository.entry(@path, @rev)
|
||||||
show_error_not_found and return unless @entry
|
show_error_not_found and return unless @entry
|
||||||
@changesets = @repository.changesets_for_path(@path, :limit => Setting.repository_log_display_limit.to_i)
|
@changesets = @repository.changesets_for_path(@path)
|
||||||
@properties = @repository.properties(@path, @rev)
|
@properties = @repository.properties(@path, @rev)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ class SearchController < ApplicationController
|
|||||||
when 'my_projects'
|
when 'my_projects'
|
||||||
User.current.memberships.collect(&:project)
|
User.current.memberships.collect(&:project)
|
||||||
when 'subprojects'
|
when 'subprojects'
|
||||||
@project ? (@project.self_and_descendants.active) : nil
|
@project ? ([ @project ] + @project.active_children) : nil
|
||||||
else
|
else
|
||||||
@project
|
@project
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class SettingsController < ApplicationController
|
|||||||
@deliveries = ActionMailer::Base.perform_deliveries
|
@deliveries = ActionMailer::Base.perform_deliveries
|
||||||
|
|
||||||
@guessed_host_and_path = request.host_with_port.dup
|
@guessed_host_and_path = request.host_with_port.dup
|
||||||
@guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank?
|
@guessed_host_and_path << ('/'+ request.relative_url_root.gsub(%r{^\/}, '')) unless request.relative_url_root.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
def plugin
|
def plugin
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
# Redmine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2009 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 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
|
||||||
@@ -16,35 +16,31 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class SysController < ActionController::Base
|
class SysController < ActionController::Base
|
||||||
before_filter :check_enabled
|
wsdl_service_name 'Sys'
|
||||||
|
web_service_api SysApi
|
||||||
|
web_service_scaffold :invoke
|
||||||
|
|
||||||
def projects
|
before_invocation :check_enabled
|
||||||
p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
|
|
||||||
render :xml => p.to_xml(:include => :repository)
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_project_repository
|
# Returns the projects list, with their repositories
|
||||||
project = Project.find(params[:id])
|
def projects_with_repository_enabled
|
||||||
if project.repository
|
Project.has_module(:repository).find(:all, :include => :repository, :order => 'identifier')
|
||||||
render :nothing => true, :status => 409
|
|
||||||
else
|
|
||||||
logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}."
|
|
||||||
project.repository = Repository.factory(params[:vendor], params[:repository])
|
|
||||||
if project.repository && project.repository.save
|
|
||||||
render :xml => project.repository, :status => 201
|
|
||||||
else
|
|
||||||
render :nothing => true, :status => 422
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
# Registers a repository for the given project identifier
|
||||||
|
def repository_created(identifier, vendor, url)
|
||||||
|
project = Project.find_by_identifier(identifier)
|
||||||
|
# Do not create the repository if the project has already one
|
||||||
|
return 0 unless project && project.repository.nil?
|
||||||
|
logger.debug "Repository for #{project.name} was created"
|
||||||
|
repository = Repository.factory(vendor, :project => project, :url => url)
|
||||||
|
repository.save
|
||||||
|
repository.id || 0
|
||||||
|
end
|
||||||
|
|
||||||
def check_enabled
|
protected
|
||||||
User.current = nil
|
|
||||||
unless Setting.sys_api_enabled?
|
def check_enabled(name, args)
|
||||||
render :nothing => 'Access denied. Repository management WS is disabled.', :status => 403
|
Setting.sys_api_enabled?
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class TimelogController < ApplicationController
|
|||||||
sql << " WHERE"
|
sql << " WHERE"
|
||||||
sql << " (%s) AND" % @project.project_condition(Setting.display_subprojects_issues?) if @project
|
sql << " (%s) AND" % @project.project_condition(Setting.display_subprojects_issues?) if @project
|
||||||
sql << " (%s) AND" % Project.allowed_to_condition(User.current, :view_time_entries)
|
sql << " (%s) AND" % Project.allowed_to_condition(User.current, :view_time_entries)
|
||||||
sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from.to_time), ActiveRecord::Base.connection.quoted_date(@to.to_time)]
|
sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)]
|
||||||
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on"
|
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on"
|
||||||
|
|
||||||
@hours = ActiveRecord::Base.connection.select_all(sql)
|
@hours = ActiveRecord::Base.connection.select_all(sql)
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -40,10 +40,8 @@ class TrackersController < ApplicationController
|
|||||||
end
|
end
|
||||||
flash[:notice] = l(:notice_successful_create)
|
flash[:notice] = l(:notice_successful_create)
|
||||||
redirect_to :action => 'list'
|
redirect_to :action => 'list'
|
||||||
return
|
|
||||||
end
|
end
|
||||||
@trackers = Tracker.find :all, :order => 'position'
|
@trackers = Tracker.find :all, :order => 'position'
|
||||||
@projects = Project.find(:all)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def edit
|
def edit
|
||||||
@@ -51,9 +49,7 @@ class TrackersController < ApplicationController
|
|||||||
if request.post? and @tracker.update_attributes(params[:tracker])
|
if request.post? and @tracker.update_attributes(params[:tracker])
|
||||||
flash[:notice] = l(:notice_successful_update)
|
flash[:notice] = l(:notice_successful_update)
|
||||||
redirect_to :action => 'list'
|
redirect_to :action => 'list'
|
||||||
return
|
|
||||||
end
|
end
|
||||||
@projects = Project.find(:all)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def move
|
def move
|
||||||
|
|||||||
@@ -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]))
|
||||||
@@ -83,7 +87,7 @@ class UsersController < ApplicationController
|
|||||||
end
|
end
|
||||||
@auth_sources = AuthSource.find(:all)
|
@auth_sources = AuthSource.find(:all)
|
||||||
@roles = Role.find_all_givable
|
@roles = Role.find_all_givable
|
||||||
@projects = Project.active.find(:all, :order => 'lft')
|
@projects = Project.find(:all, :order => 'name', :conditions => "status=#{Project::STATUS_ACTIVE}") - @user.projects
|
||||||
@membership ||= Member.new
|
@membership ||= Member.new
|
||||||
@memberships = @user.memberships
|
@memberships = @user.memberships
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,15 +16,9 @@
|
|||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
class WelcomeController < ApplicationController
|
class WelcomeController < ApplicationController
|
||||||
caches_action :robots
|
|
||||||
|
|
||||||
def index
|
def index
|
||||||
@news = News.latest User.current
|
@news = News.latest User.current
|
||||||
@projects = Project.latest User.current
|
@projects = Project.latest User.current
|
||||||
end
|
end
|
||||||
|
|
||||||
def robots
|
|
||||||
@projects = Project.public.active
|
|
||||||
render :layout => false, :content_type => 'text/plain'
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -45,11 +45,11 @@ class WikiController < ApplicationController
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
@content = @page.content_for_version(params[:version])
|
@content = @page.content_for_version(params[:version])
|
||||||
if params[:format] == 'html'
|
if params[:export] == 'html'
|
||||||
export = render_to_string :action => 'export', :layout => false
|
export = render_to_string :action => 'export', :layout => false
|
||||||
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
|
||||||
return
|
return
|
||||||
elsif params[:format] == 'txt'
|
elsif params[:export] == 'txt'
|
||||||
send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
|
send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -20,12 +20,4 @@ module AdminHelper
|
|||||||
options_for_select([[l(:label_all), ''],
|
options_for_select([[l(:label_all), ''],
|
||||||
[l(:status_active), 1]], selected)
|
[l(:status_active), 1]], selected)
|
||||||
end
|
end
|
||||||
|
|
||||||
def css_project_classes(project)
|
|
||||||
s = 'project'
|
|
||||||
s << ' root' if project.root?
|
|
||||||
s << ' child' if project.child?
|
|
||||||
s << (project.leaf? ? ' leaf' : ' parent')
|
|
||||||
s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def format_activity_description(text)
|
def format_activity_description(text)
|
||||||
h(truncate(text.to_s, 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "<br />")
|
h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...'))
|
||||||
end
|
end
|
||||||
|
|
||||||
def distance_of_date_in_words(from_date, to_date = 0)
|
def distance_of_date_in_words(from_date, to_date = 0)
|
||||||
@@ -156,73 +156,10 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
s
|
s
|
||||||
end
|
end
|
||||||
|
|
||||||
# Renders the project quick-jump box
|
|
||||||
def render_project_jump_box
|
|
||||||
# Retrieve them now to avoid a COUNT query
|
|
||||||
projects = User.current.projects.all
|
|
||||||
if projects.any?
|
|
||||||
s = '<select onchange="if (this.value != \'\') { window.location = this.value; }">' +
|
|
||||||
"<option selected='selected'>#{ l(:label_jump_to_a_project) }</option>" +
|
|
||||||
'<option disabled="disabled">---</option>'
|
|
||||||
s << project_tree_options_for_select(projects) do |p|
|
|
||||||
{ :value => url_for(:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item) }
|
|
||||||
end
|
|
||||||
s << '</select>'
|
|
||||||
s
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def project_tree_options_for_select(projects, options = {})
|
|
||||||
s = ''
|
|
||||||
project_tree(projects) do |project, level|
|
|
||||||
name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '')
|
|
||||||
tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)}
|
|
||||||
tag_options.merge!(yield(project)) if block_given?
|
|
||||||
s << content_tag('option', name_prefix + h(project), tag_options)
|
|
||||||
end
|
|
||||||
s
|
|
||||||
end
|
|
||||||
|
|
||||||
# Yields the given block for each project with its level in the tree
|
|
||||||
def project_tree(projects, &block)
|
|
||||||
ancestors = []
|
|
||||||
projects.sort_by(&:lft).each do |project|
|
|
||||||
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
|
||||||
ancestors.pop
|
|
||||||
end
|
|
||||||
yield project, ancestors.size
|
|
||||||
ancestors << project
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def project_nested_ul(projects, &block)
|
|
||||||
s = ''
|
|
||||||
if projects.any?
|
|
||||||
ancestors = []
|
|
||||||
projects.sort_by(&:lft).each do |project|
|
|
||||||
if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
|
|
||||||
s << "<ul>\n"
|
|
||||||
else
|
|
||||||
ancestors.pop
|
|
||||||
s << "</li>"
|
|
||||||
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
|
||||||
ancestors.pop
|
|
||||||
s << "</ul></li>\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
s << "<li>"
|
|
||||||
s << yield(project).to_s
|
|
||||||
ancestors << project
|
|
||||||
end
|
|
||||||
s << ("</li></ul>\n" * ancestors.size)
|
|
||||||
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)
|
||||||
truncate(string, *args).gsub(%r{[\r\n]+}m, ' ')
|
truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def html_hours(text)
|
def html_hours(text)
|
||||||
@@ -263,40 +200,43 @@ module ApplicationHelper
|
|||||||
def pagination_links_full(paginator, count=nil, options={})
|
def pagination_links_full(paginator, count=nil, options={})
|
||||||
page_param = options.delete(:page_param) || :page
|
page_param = options.delete(:page_param) || :page
|
||||||
url_param = params.dup
|
url_param = params.dup
|
||||||
# don't reuse query params if filters are present
|
# don't reuse params if filters are present
|
||||||
url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter)
|
url_param.clear if url_param.has_key?(:set_filter)
|
||||||
|
|
||||||
html = ''
|
html = ''
|
||||||
if paginator.current.previous
|
html << link_to_remote(('« ' + l(:label_previous)),
|
||||||
html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' '
|
{:update => 'content',
|
||||||
end
|
:url => url_param.merge(page_param => paginator.current.previous),
|
||||||
|
:complete => 'window.scrollTo(0,0)'},
|
||||||
|
{:href => url_for(:params => url_param.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous
|
||||||
|
|
||||||
html << (pagination_links_each(paginator, options) do |n|
|
html << (pagination_links_each(paginator, options) do |n|
|
||||||
link_to_remote_content_update(n.to_s, url_param.merge(page_param => n))
|
link_to_remote(n.to_s,
|
||||||
|
{:url => {:params => url_param.merge(page_param => n)},
|
||||||
|
:update => 'content',
|
||||||
|
:complete => 'window.scrollTo(0,0)'},
|
||||||
|
{:href => url_for(:params => url_param.merge(page_param => n))})
|
||||||
end || '')
|
end || '')
|
||||||
|
|
||||||
if paginator.current.next
|
html << ' ' + link_to_remote((l(:label_next) + ' »'),
|
||||||
html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next))
|
{:update => 'content',
|
||||||
end
|
:url => url_param.merge(page_param => paginator.current.next),
|
||||||
|
:complete => 'window.scrollTo(0,0)'},
|
||||||
|
{:href => url_for(:params => url_param.merge(page_param => paginator.current.next))}) if paginator.current.next
|
||||||
|
|
||||||
unless count.nil?
|
unless count.nil?
|
||||||
html << [
|
html << [" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", per_page_links(paginator.items_per_page)].compact.join(' | ')
|
||||||
" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})",
|
|
||||||
per_page_links(paginator.items_per_page)
|
|
||||||
].compact.join(' | ')
|
|
||||||
end
|
end
|
||||||
|
|
||||||
html
|
html
|
||||||
end
|
end
|
||||||
|
|
||||||
def per_page_links(selected=nil)
|
def per_page_links(selected=nil)
|
||||||
url_param = params.dup
|
url_param = params.dup
|
||||||
url_param.clear if url_param.has_key?(:set_filter)
|
url_param.clear if url_param.has_key?(:set_filter)
|
||||||
|
|
||||||
links = Setting.per_page_options_array.collect do |n|
|
links = Setting.per_page_options_array.collect do |n|
|
||||||
n == selected ? n : link_to_remote(n, {:update => "content",
|
n == selected ? n : link_to_remote(n, {:update => "content", :url => params.dup.merge(:per_page => n)},
|
||||||
:url => params.dup.merge(:per_page => n),
|
|
||||||
:method => :get},
|
|
||||||
{:href => url_for(url_param.merge(:per_page => n))})
|
{:href => url_for(url_param.merge(:per_page => n))})
|
||||||
end
|
end
|
||||||
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
|
links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil
|
||||||
@@ -306,12 +246,6 @@ module ApplicationHelper
|
|||||||
elements = args.flatten
|
elements = args.flatten
|
||||||
elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil
|
elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def other_formats_links(&block)
|
|
||||||
concat('<p class="other-formats">' + l(:label_export_to), block.binding)
|
|
||||||
yield Redmine::Views::OtherFormatsBuilder.new(self)
|
|
||||||
concat('</p>', block.binding)
|
|
||||||
end
|
|
||||||
|
|
||||||
def html_title(*args)
|
def html_title(*args)
|
||||||
if args.empty?
|
if args.empty?
|
||||||
@@ -418,7 +352,7 @@ module ApplicationHelper
|
|||||||
:class => ('wiki-page' + (wiki_page ? '' : ' new')))
|
:class => ('wiki-page' + (wiki_page ? '' : ' new')))
|
||||||
else
|
else
|
||||||
# project or wiki doesn't exist
|
# project or wiki doesn't exist
|
||||||
all
|
title || page
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
all
|
all
|
||||||
@@ -451,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?
|
||||||
@@ -553,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 << "« " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " » " + l(msg) unless attr == "custom_values"
|
full_messages << "« " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " » " + l(*msg) unless attr == "custom_values"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
# retrieve custom values error messages
|
# retrieve custom values error messages
|
||||||
@@ -565,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 << "« " + v.custom_field.name + " » " + l(msg)
|
full_messages << "« " + v.custom_field.name + " » " + l(*msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -690,12 +624,4 @@ module ApplicationHelper
|
|||||||
extend helper
|
extend helper
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
def link_to_remote_content_update(text, url_params)
|
|
||||||
link_to_remote(text,
|
|
||||||
{:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'},
|
|
||||||
{:href => url_for(:params => url_params)}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ module IssuesHelper
|
|||||||
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 << ' 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
|
||||||
|
|
||||||
|
|||||||
@@ -33,39 +33,4 @@ module ProjectsHelper
|
|||||||
]
|
]
|
||||||
tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
|
tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
|
||||||
end
|
end
|
||||||
|
|
||||||
def parent_project_select_tag(project)
|
|
||||||
options = '<option></option>' + project_tree_options_for_select(project.possible_parents, :selected => project.parent)
|
|
||||||
content_tag('select', options, :name => 'project[parent_id]')
|
|
||||||
end
|
|
||||||
|
|
||||||
# Renders a tree of projects as a nested set of unordered lists
|
|
||||||
# The given collection may be a subset of the whole project tree
|
|
||||||
# (eg. some intermediate nodes are private and can not be seen)
|
|
||||||
def render_project_hierarchy(projects)
|
|
||||||
s = ''
|
|
||||||
if projects.any?
|
|
||||||
ancestors = []
|
|
||||||
projects.each do |project|
|
|
||||||
if (ancestors.empty? || project.is_descendant_of?(ancestors.last))
|
|
||||||
s << "<ul class='projects #{ ancestors.empty? ? 'root' : nil}'>\n"
|
|
||||||
else
|
|
||||||
ancestors.pop
|
|
||||||
s << "</li>"
|
|
||||||
while (ancestors.any? && !project.is_descendant_of?(ancestors.last))
|
|
||||||
ancestors.pop
|
|
||||||
s << "</ul></li>\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
classes = (ancestors.empty? ? 'root' : 'child')
|
|
||||||
s << "<li class='#{classes}'><div class='#{classes}'>" +
|
|
||||||
link_to(h(project), {:controller => 'projects', :action => 'show', :id => project}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}")
|
|
||||||
s << "<div class='wiki description'>#{textilizable(project.short_description, :project => project)}</div>" unless project.description.blank?
|
|
||||||
s << "</div>\n"
|
|
||||||
ancestors << project
|
|
||||||
end
|
|
||||||
s << ("</li></ul>\n" * ancestors.size)
|
|
||||||
end
|
|
||||||
s
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -147,13 +147,12 @@ 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)),
|
||||||
:onfocus => "this.value=''; this.name='repository[password]';",
|
:onfocus => "this.value=''; this.name='repository[password]';",
|
||||||
:onchange => "this.name='repository[password]';")) +
|
:onchange => "this.name='repository[password]';"))
|
||||||
content_tag('p', form.check_box(:cache))
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def darcs_field_tags(form, repository)
|
def darcs_field_tags(form, repository)
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ module SearchHelper
|
|||||||
def project_select_tag
|
def project_select_tag
|
||||||
options = [[l(:label_project_all), 'all']]
|
options = [[l(:label_project_all), 'all']]
|
||||||
options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?
|
options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty?
|
||||||
options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty?
|
options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.active_children.empty?
|
||||||
options << [@project.name, ''] unless @project.nil?
|
options << [@project.name, ''] unless @project.nil?
|
||||||
select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1
|
select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
module SettingsHelper
|
module SettingsHelper
|
||||||
def administration_settings_tabs
|
def administration_settings_tabs
|
||||||
tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general},
|
tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general},
|
||||||
{:name => 'display', :partial => 'settings/display', :label => :label_display},
|
|
||||||
{:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication},
|
{:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication},
|
||||||
{:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural},
|
{:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural},
|
||||||
{:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking},
|
{:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking},
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ module SortHelper
|
|||||||
session[@sort_name] = sort
|
session[@sort_name] = sort
|
||||||
|
|
||||||
sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key])
|
sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key])
|
||||||
@sort_clause = (sort_column.blank? ? nil : [sort_column].flatten.collect {|s| "#{s} #{sort[:order]}"}.join(','))
|
@sort_clause = (sort_column.blank? ? nil : "#{sort_column} #{sort[:order]}")
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an SQL sort clause corresponding to the current sort state.
|
# Returns an SQL sort clause corresponding to the current sort state.
|
||||||
@@ -120,11 +120,8 @@ module SortHelper
|
|||||||
# don't reuse params if filters are present
|
# don't reuse params if filters are present
|
||||||
url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)
|
url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options)
|
||||||
|
|
||||||
# Add project_id to url_options
|
|
||||||
url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id)
|
|
||||||
|
|
||||||
link_to_remote(caption,
|
link_to_remote(caption,
|
||||||
{:update => "content", :url => url_options, :method => :get},
|
{:update => "content", :url => url_options},
|
||||||
{:href => url_for(url_options)}) +
|
{:href => url_for(url_options)}) +
|
||||||
(icon ? nbsp(2) + image_tag(icon) : '')
|
(icon ? nbsp(2) + image_tag(icon) : '')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,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)
|
||||||
|
|||||||
@@ -25,10 +25,15 @@ module UsersHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Options for the new membership projects combo-box
|
# Options for the new membership projects combo-box
|
||||||
def options_for_membership_project_select(user, projects)
|
def projects_options_for_select(projects)
|
||||||
options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
|
options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---")
|
||||||
options << project_tree_options_for_select(projects) do |p|
|
projects_by_root = projects.group_by(&:root)
|
||||||
{:disabled => (user.projects.include?(p))}
|
projects_by_root.keys.sort.each do |root|
|
||||||
|
options << content_tag('option', h(root.name), :value => root.id, :disabled => (!projects.include?(root)))
|
||||||
|
projects_by_root[root].sort.each do |project|
|
||||||
|
next if project == root
|
||||||
|
options << content_tag('option', '» ' + h(project.name), :value => project.id)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
options
|
options
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+10
-11
@@ -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
|
||||||
@@ -141,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
|
||||||
|
|||||||
+4
-16
@@ -23,8 +23,8 @@ class Changeset < ActiveRecord::Base
|
|||||||
has_many :changes, :dependent => :delete_all
|
has_many :changes, :dependent => :delete_all
|
||||||
has_and_belongs_to_many :issues
|
has_and_belongs_to_many :issues
|
||||||
|
|
||||||
acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))},
|
acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.comments.blank? ? '' : (': ' + o.comments))},
|
||||||
:description => :long_comments,
|
:description => :comments,
|
||||||
:datetime => :committed_on,
|
:datetime => :committed_on,
|
||||||
:url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}}
|
:url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -122,14 +124,6 @@ class Changeset < ActiveRecord::Base
|
|||||||
self.issues = referenced_issues.uniq
|
self.issues = referenced_issues.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
def short_comments
|
|
||||||
@short_comments || split_comments.first
|
|
||||||
end
|
|
||||||
|
|
||||||
def long_comments
|
|
||||||
@long_comments || split_comments.last
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the previous changeset
|
# Returns the previous changeset
|
||||||
def previous
|
def previous
|
||||||
@previous ||= Changeset.find(:first, :conditions => ['id < ? AND repository_id = ?', self.id, self.repository_id], :order => 'id DESC')
|
@previous ||= Changeset.find(:first, :conditions => ['id < ? AND repository_id = ?', self.id, self.repository_id], :order => 'id DESC')
|
||||||
@@ -147,12 +141,6 @@ class Changeset < ActiveRecord::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def split_comments
|
|
||||||
comments =~ /\A(.+?)\r?\n(.*)$/m
|
|
||||||
@short_comments = $1 || comments
|
|
||||||
@long_comments = $2.to_s.strip
|
|
||||||
return @short_comments, @long_comments
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.to_utf8(str)
|
def self.to_utf8(str)
|
||||||
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
|
return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ class CustomField < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def before_validation
|
def before_validation
|
||||||
|
# remove empty values
|
||||||
|
self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
|
||||||
# make sure these fields are not searchable
|
# make sure these fields are not searchable
|
||||||
self.searchable = false if %w(int float date bool).include?(field_format)
|
self.searchable = false if %w(int float date bool).include?(field_format)
|
||||||
true
|
true
|
||||||
@@ -57,49 +59,11 @@ class CustomField < ActiveRecord::Base
|
|||||||
v.custom_field.is_required = false
|
v.custom_field.is_required = false
|
||||||
errors.add(:default_value, :activerecord_error_invalid) unless v.valid?
|
errors.add(:default_value, :activerecord_error_invalid) unless v.valid?
|
||||||
end
|
end
|
||||||
|
|
||||||
# Makes possible_values accept a multiline string
|
|
||||||
def possible_values=(arg)
|
|
||||||
if arg.is_a?(Array)
|
|
||||||
write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?})
|
|
||||||
else
|
|
||||||
self.possible_values = arg.to_s.split(/[\n\r]+/)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns a ORDER BY clause that can used to sort customized
|
|
||||||
# objects by their value of the custom field.
|
|
||||||
# Returns false, if the custom field can not be used for sorting.
|
|
||||||
def order_statement
|
|
||||||
case field_format
|
|
||||||
when 'string', 'text', 'list', 'date', 'bool'
|
|
||||||
# COALESCE is here to make sure that blank and NULL values are sorted equally
|
|
||||||
"COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" +
|
|
||||||
" WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
|
|
||||||
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
|
|
||||||
" AND cv_sort.custom_field_id=#{id} LIMIT 1), '')"
|
|
||||||
when 'int', 'float'
|
|
||||||
# Make the database cast values into numeric
|
|
||||||
# Postgresql will raise an error if a value can not be casted!
|
|
||||||
# CustomValue validations should ensure that it doesn't occur
|
|
||||||
"(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" +
|
|
||||||
" WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" +
|
|
||||||
" AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" +
|
|
||||||
" AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)"
|
|
||||||
else
|
|
||||||
nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def <=>(field)
|
def <=>(field)
|
||||||
position <=> field.position
|
position <=> field.position
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.customized_class
|
|
||||||
self.name =~ /^(.+)CustomField$/
|
|
||||||
begin; $1.constantize; rescue nil; end
|
|
||||||
end
|
|
||||||
|
|
||||||
# to move in project_custom_field
|
# to move in project_custom_field
|
||||||
def self.for_all
|
def self.for_all
|
||||||
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
|
find(:all, :conditions => ["is_for_all=?", true], :order => 'position')
|
||||||
|
|||||||
@@ -30,18 +30,6 @@ class CustomValue < ActiveRecord::Base
|
|||||||
self.value == '1'
|
self.value == '1'
|
||||||
end
|
end
|
||||||
|
|
||||||
def editable?
|
|
||||||
custom_field.editable?
|
|
||||||
end
|
|
||||||
|
|
||||||
def required?
|
|
||||||
custom_field.is_required?
|
|
||||||
end
|
|
||||||
|
|
||||||
def to_s
|
|
||||||
value.to_s
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
protected
|
||||||
def validate
|
def validate
|
||||||
if value.blank?
|
if value.blank?
|
||||||
|
|||||||
+23
-35
@@ -40,8 +40,7 @@ class Issue < ActiveRecord::Base
|
|||||||
# sort by id so that limited eager loading doesn't break with postgresql
|
# sort by id so that limited eager loading doesn't break with postgresql
|
||||||
:order_column => "#{table_name}.id"
|
:order_column => "#{table_name}.id"
|
||||||
acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
|
acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"},
|
||||||
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}},
|
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}
|
||||||
:type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }
|
|
||||||
|
|
||||||
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
|
||||||
@@ -51,14 +50,6 @@ class Issue < ActiveRecord::Base
|
|||||||
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
|
||||||
|
|
||||||
named_scope :visible, lambda {|*args| { :include => :project,
|
|
||||||
:conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } }
|
|
||||||
|
|
||||||
# Returns true if usr or current user is allowed to view the issue
|
|
||||||
def visible?(usr=nil)
|
|
||||||
(usr || User.current).allowed_to?(:view_issues, self.project)
|
|
||||||
end
|
|
||||||
|
|
||||||
def after_initialize
|
def after_initialize
|
||||||
if new_record?
|
if new_record?
|
||||||
# set default values for new records only
|
# set default values for new records only
|
||||||
@@ -79,43 +70,34 @@ class Issue < ActiveRecord::Base
|
|||||||
self
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
# Moves/copies an issue to a new project and tracker
|
# Move an issue to a new project and tracker
|
||||||
# Returns the moved/copied issue on success, false on failure
|
def move_to(new_project, new_tracker = nil)
|
||||||
def move_to(new_project, new_tracker = nil, options = {})
|
|
||||||
options ||= {}
|
|
||||||
issue = options[:copy] ? self.clone : self
|
|
||||||
transaction do
|
transaction do
|
||||||
if new_project && issue.project_id != new_project.id
|
if new_project && project_id != new_project.id
|
||||||
# delete issue relations
|
# delete issue relations
|
||||||
unless Setting.cross_project_issue_relations?
|
unless Setting.cross_project_issue_relations?
|
||||||
issue.relations_from.clear
|
self.relations_from.clear
|
||||||
issue.relations_to.clear
|
self.relations_to.clear
|
||||||
end
|
end
|
||||||
# issue is moved to another project
|
# issue is moved to another project
|
||||||
# reassign to the category with same name if any
|
# reassign to the category with same name if any
|
||||||
new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name)
|
new_category = category.nil? ? nil : new_project.issue_categories.find_by_name(category.name)
|
||||||
issue.category = new_category
|
self.category = new_category
|
||||||
issue.fixed_version = nil
|
self.fixed_version = nil
|
||||||
issue.project = new_project
|
self.project = new_project
|
||||||
end
|
end
|
||||||
if new_tracker
|
if new_tracker
|
||||||
issue.tracker = new_tracker
|
self.tracker = new_tracker
|
||||||
end
|
end
|
||||||
if options[:copy]
|
if save
|
||||||
issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h}
|
# Manually update project_id on related time entries
|
||||||
issue.status = self.status
|
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
|
||||||
end
|
|
||||||
if issue.save
|
|
||||||
unless options[:copy]
|
|
||||||
# Manually update project_id on related time entries
|
|
||||||
TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id})
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
Issue.connection.rollback_db_transaction
|
rollback_db_transaction
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return issue
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
def priority_id=(pid)
|
def priority_id=(pid)
|
||||||
@@ -215,7 +197,7 @@ class Issue < ActiveRecord::Base
|
|||||||
|
|
||||||
# Returns true if the issue is overdue
|
# Returns true if the issue is overdue
|
||||||
def overdue?
|
def overdue?
|
||||||
!due_date.nil? && (due_date < Date.today) && !status.is_closed?
|
!due_date.nil? && (due_date < Date.today)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Users the issue can be assigned to
|
# Users the issue can be assigned to
|
||||||
@@ -275,6 +257,12 @@ class Issue < ActiveRecord::Base
|
|||||||
@soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
|
@soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.visible_by(usr)
|
||||||
|
with_scope(:find => { :conditions => Project.visible_by(usr) }) do
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"#{tracker} ##{id}: #{subject}"
|
"#{tracker} ##{id}: #{subject}"
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -35,8 +35,6 @@ class IssueRelation < ActiveRecord::Base
|
|||||||
validates_numericality_of :delay, :allow_nil => true
|
validates_numericality_of :delay, :allow_nil => true
|
||||||
validates_uniqueness_of :issue_to_id, :scope => :issue_from_id
|
validates_uniqueness_of :issue_to_id, :scope => :issue_from_id
|
||||||
|
|
||||||
attr_protected :issue_from_id, :issue_to_id
|
|
||||||
|
|
||||||
def validate
|
def validate
|
||||||
if issue_from && issue_to
|
if issue_from && issue_to
|
||||||
errors.add :issue_to_id, :activerecord_error_invalid if issue_from_id == issue_to_id
|
errors.add :issue_to_id, :activerecord_error_invalid if issue_from_id == issue_to_id
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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_by_mail(email.from.first.to_s.strip)
|
@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
|
||||||
@@ -53,24 +53,11 @@ class MailHandler < ActionMailer::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
MESSAGE_ID_RE = %r{^<redmine\.([a-z0-9_]+)\-(\d+)\.\d+@}
|
|
||||||
ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
|
ISSUE_REPLY_SUBJECT_RE = %r{\[[^\]]+#(\d+)\]}
|
||||||
MESSAGE_REPLY_SUBJECT_RE = %r{\[[^\]]+msg(\d+)\]}
|
|
||||||
|
|
||||||
def dispatch
|
def dispatch
|
||||||
headers = [email.in_reply_to, email.references].flatten.compact
|
if m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
|
||||||
if headers.detect {|h| h.to_s =~ MESSAGE_ID_RE}
|
receive_issue_update(m[1].to_i)
|
||||||
klass, object_id = $1, $2.to_i
|
|
||||||
method_name = "receive_#{klass}_reply"
|
|
||||||
if self.class.private_instance_methods.include?(method_name)
|
|
||||||
send method_name, object_id
|
|
||||||
else
|
|
||||||
# ignoring it
|
|
||||||
end
|
|
||||||
elsif m = email.subject.match(ISSUE_REPLY_SUBJECT_RE)
|
|
||||||
receive_issue_reply(m[1].to_i)
|
|
||||||
elsif m = email.subject.match(MESSAGE_REPLY_SUBJECT_RE)
|
|
||||||
receive_message_reply(m[1].to_i)
|
|
||||||
else
|
else
|
||||||
receive_issue
|
receive_issue
|
||||||
end
|
end
|
||||||
@@ -130,7 +117,7 @@ class MailHandler < ActionMailer::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Adds a note to an existing issue
|
# Adds a note to an existing issue
|
||||||
def receive_issue_reply(issue_id)
|
def receive_issue_update(issue_id)
|
||||||
status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
|
status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status)))
|
||||||
|
|
||||||
issue = Issue.find_by_id(issue_id)
|
issue = Issue.find_by_id(issue_id)
|
||||||
@@ -152,33 +139,6 @@ class MailHandler < ActionMailer::Base
|
|||||||
journal
|
journal
|
||||||
end
|
end
|
||||||
|
|
||||||
# Reply will be added to the issue
|
|
||||||
def receive_journal_reply(journal_id)
|
|
||||||
journal = Journal.find_by_id(journal_id)
|
|
||||||
if journal && journal.journalized_type == 'Issue'
|
|
||||||
receive_issue_reply(journal.journalized_id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Receives a reply to a forum message
|
|
||||||
def receive_message_reply(message_id)
|
|
||||||
message = Message.find_by_id(message_id)
|
|
||||||
if message
|
|
||||||
message = message.root
|
|
||||||
if user.allowed_to?(:add_messages, message.project) && !message.locked?
|
|
||||||
reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip,
|
|
||||||
:content => plain_text_body)
|
|
||||||
reply.author = user
|
|
||||||
reply.board = message.board
|
|
||||||
message.children << reply
|
|
||||||
add_attachments(reply)
|
|
||||||
reply
|
|
||||||
else
|
|
||||||
raise UnauthorizedAction
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def add_attachments(obj)
|
def add_attachments(obj)
|
||||||
if email.has_attachments?
|
if email.has_attachments?
|
||||||
email.attachments.each do |attachment|
|
email.attachments.each do |attachment|
|
||||||
@@ -208,7 +168,7 @@ class MailHandler < ActionMailer::Base
|
|||||||
@keywords[attr]
|
@keywords[attr]
|
||||||
else
|
else
|
||||||
@keywords[attr] = begin
|
@keywords[attr] = begin
|
||||||
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}:[ \t]*(.+)\s*$/i, '')
|
if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}[ \t]*:[ \t]*(.+)\s*$/i, '')
|
||||||
$1.strip
|
$1.strip
|
||||||
elsif !@@handler_options[:issue][attr].blank?
|
elsif !@@handler_options[:issue][attr].blank?
|
||||||
@@handler_options[:issue][attr]
|
@@handler_options[:issue][attr]
|
||||||
@@ -235,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
|
||||||
|
|||||||
+21
-54
@@ -22,12 +22,17 @@ 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
|
||||||
message_id issue
|
|
||||||
recipients issue.recipients
|
recipients issue.recipients
|
||||||
cc(issue.watcher_recipients - @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}"
|
||||||
@@ -41,8 +46,6 @@ 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
|
||||||
message_id journal
|
|
||||||
references issue
|
|
||||||
@author = journal.user
|
@author = journal.user
|
||||||
recipients issue.recipients
|
recipients issue.recipients
|
||||||
# Watchers in cc
|
# Watchers in cc
|
||||||
@@ -98,7 +101,6 @@ class Mailer < ActionMailer::Base
|
|||||||
|
|
||||||
def news_added(news)
|
def news_added(news)
|
||||||
redmine_headers 'Project' => news.project.identifier
|
redmine_headers 'Project' => news.project.identifier
|
||||||
message_id news
|
|
||||||
recipients news.project.recipients
|
recipients news.project.recipients
|
||||||
subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
|
subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}"
|
||||||
body :news => news,
|
body :news => news,
|
||||||
@@ -108,10 +110,8 @@ class Mailer < ActionMailer::Base
|
|||||||
def message_posted(message, recipients)
|
def message_posted(message, recipients)
|
||||||
redmine_headers 'Project' => message.project.identifier,
|
redmine_headers 'Project' => message.project.identifier,
|
||||||
'Topic-Id' => (message.parent_id || message.id)
|
'Topic-Id' => (message.parent_id || message.id)
|
||||||
message_id message
|
|
||||||
references message.parent unless message.parent.nil?
|
|
||||||
recipients(recipients)
|
recipients(recipients)
|
||||||
subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}"
|
subject "[#{message.board.project.name} - #{message.board.name}] #{message.subject}"
|
||||||
body :message => message,
|
body :message => message,
|
||||||
:message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
|
:message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root)
|
||||||
end
|
end
|
||||||
@@ -133,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
|
||||||
@@ -162,15 +171,7 @@ class Mailer < ActionMailer::Base
|
|||||||
return false if (recipients.nil? || recipients.empty?) &&
|
return false if (recipients.nil? || recipients.empty?) &&
|
||||||
(cc.nil? || cc.empty?) &&
|
(cc.nil? || cc.empty?) &&
|
||||||
(bcc.nil? || bcc.empty?)
|
(bcc.nil? || bcc.empty?)
|
||||||
|
super
|
||||||
# Set Message-Id and References
|
|
||||||
if @message_id_object
|
|
||||||
mail.message_id = self.class.message_id_for(@message_id_object)
|
|
||||||
end
|
|
||||||
if @references_objects
|
|
||||||
mail.references = @references_objects.collect {|o| self.class.message_id_for(o)}
|
|
||||||
end
|
|
||||||
super(mail)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sends reminders to issue assignees
|
# Sends reminders to issue assignees
|
||||||
@@ -203,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 Redmine::Utils.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-')
|
||||||
@@ -240,7 +237,7 @@ class Mailer < ActionMailer::Base
|
|||||||
|
|
||||||
# Renders a message with the corresponding layout
|
# Renders a message with the corresponding layout
|
||||||
def render_message(method_name, body)
|
def render_message(method_name, body)
|
||||||
layout = method_name.to_s.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
|
layout = method_name.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml'
|
||||||
body[:content_for_layout] = render(:file => method_name, :body => body)
|
body[:content_for_layout] = render(:file => method_name, :body => body)
|
||||||
ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
|
ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true)
|
||||||
end
|
end
|
||||||
@@ -264,34 +261,4 @@ class Mailer < ActionMailer::Base
|
|||||||
def self.controller_path
|
def self.controller_path
|
||||||
''
|
''
|
||||||
end unless respond_to?('controller_path')
|
end unless respond_to?('controller_path')
|
||||||
|
|
||||||
# Returns a predictable Message-Id for the given object
|
|
||||||
def self.message_id_for(object)
|
|
||||||
# id + timestamp should reduce the odds of a collision
|
|
||||||
# as far as we don't send multiple emails for the same object
|
|
||||||
hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{object.created_on.strftime("%Y%m%d%H%M%S")}"
|
|
||||||
host = Setting.mail_from.to_s.gsub(%r{^.*@}, '')
|
|
||||||
host = "#{::Socket.gethostname}.redmine" if host.empty?
|
|
||||||
"<#{hash}@#{host}>"
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def message_id(object)
|
|
||||||
@message_id_object = object
|
|
||||||
end
|
|
||||||
|
|
||||||
def references(object)
|
|
||||||
@references_objects ||= []
|
|
||||||
@references_objects << object
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Patch TMail so that message_id is not overwritten
|
|
||||||
module TMail
|
|
||||||
class Mail
|
|
||||||
def add_message_id( fqdn = nil )
|
|
||||||
self.message_id ||= ::TMail::new_message_id(fqdn)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+13
-56
@@ -43,7 +43,7 @@ class Project < ActiveRecord::Base
|
|||||||
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
|
:join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}",
|
||||||
:association_foreign_key => 'custom_field_id'
|
:association_foreign_key => 'custom_field_id'
|
||||||
|
|
||||||
acts_as_nested_set :order => 'name', :dependent => :destroy
|
acts_as_tree :order => "name", :counter_cache => true
|
||||||
acts_as_attachable :view_permission => :view_files,
|
acts_as_attachable :view_permission => :view_files,
|
||||||
:delete_permission => :manage_files
|
:delete_permission => :manage_files
|
||||||
|
|
||||||
@@ -60,15 +60,12 @@ 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 => 2..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
|
||||||
|
|
||||||
named_scope :has_module, lambda { |mod| { :conditions => ["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s] } }
|
named_scope :has_module, lambda { |mod| { :conditions => ["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s] } }
|
||||||
named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"}
|
|
||||||
named_scope :public, { :conditions => { :is_public => true } }
|
|
||||||
named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } }
|
|
||||||
|
|
||||||
def identifier=(identifier)
|
def identifier=(identifier)
|
||||||
super unless identifier_frozen?
|
super unless identifier_frozen?
|
||||||
@@ -81,7 +78,7 @@ class Project < ActiveRecord::Base
|
|||||||
def issues_with_subprojects(include_subprojects=false)
|
def issues_with_subprojects(include_subprojects=false)
|
||||||
conditions = nil
|
conditions = nil
|
||||||
if include_subprojects
|
if include_subprojects
|
||||||
ids = [id] + descendants.collect(&:id)
|
ids = [id] + child_ids
|
||||||
conditions = ["#{Project.table_name}.id IN (#{ids.join(',')}) AND #{Project.visible_by}"]
|
conditions = ["#{Project.table_name}.id IN (#{ids.join(',')}) AND #{Project.visible_by}"]
|
||||||
end
|
end
|
||||||
conditions ||= ["#{Project.table_name}.id = ?", id]
|
conditions ||= ["#{Project.table_name}.id = ?", id]
|
||||||
@@ -121,7 +118,7 @@ class Project < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
if options[:project]
|
if options[:project]
|
||||||
project_statement = "#{Project.table_name}.id = #{options[:project].id}"
|
project_statement = "#{Project.table_name}.id = #{options[:project].id}"
|
||||||
project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects]
|
project_statement << " OR #{Project.table_name}.parent_id = #{options[:project].id}" if options[:with_subprojects]
|
||||||
base_statement = "(#{project_statement}) AND (#{base_statement})"
|
base_statement = "(#{project_statement}) AND (#{base_statement})"
|
||||||
end
|
end
|
||||||
if user.admin?
|
if user.admin?
|
||||||
@@ -144,7 +141,7 @@ class Project < ActiveRecord::Base
|
|||||||
|
|
||||||
def project_condition(with_subprojects)
|
def project_condition(with_subprojects)
|
||||||
cond = "#{Project.table_name}.id = #{id}"
|
cond = "#{Project.table_name}.id = #{id}"
|
||||||
cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects
|
cond = "(#{cond} OR #{Project.table_name}.parent_id = #{id})" if with_subprojects
|
||||||
cond
|
cond
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -167,7 +164,6 @@ class Project < ActiveRecord::Base
|
|||||||
self.status == STATUS_ACTIVE
|
self.status == STATUS_ACTIVE
|
||||||
end
|
end
|
||||||
|
|
||||||
# Archives the project and its descendants recursively
|
|
||||||
def archive
|
def archive
|
||||||
# Archive subprojects if any
|
# Archive subprojects if any
|
||||||
children.each do |subproject|
|
children.each do |subproject|
|
||||||
@@ -176,62 +172,21 @@ class Project < ActiveRecord::Base
|
|||||||
update_attribute :status, STATUS_ARCHIVED
|
update_attribute :status, STATUS_ARCHIVED
|
||||||
end
|
end
|
||||||
|
|
||||||
# Unarchives the project
|
|
||||||
# All its ancestors must be active
|
|
||||||
def unarchive
|
def unarchive
|
||||||
return false if ancestors.detect {|a| !a.active?}
|
return false if parent && !parent.active?
|
||||||
update_attribute :status, STATUS_ACTIVE
|
update_attribute :status, STATUS_ACTIVE
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns an array of projects the project can be moved to
|
def active_children
|
||||||
def possible_parents
|
children.select {|child| child.active?}
|
||||||
@possible_parents ||= (Project.active.find(:all) - self_and_descendants)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sets the parent of the project
|
# Returns an array of the trackers used by the project and its sub projects
|
||||||
# Argument can be either a Project, a String, a Fixnum or nil
|
|
||||||
def set_parent!(p)
|
|
||||||
unless p.nil? || p.is_a?(Project)
|
|
||||||
if p.to_s.blank?
|
|
||||||
p = nil
|
|
||||||
else
|
|
||||||
p = Project.find_by_id(p)
|
|
||||||
return false unless p
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if p == parent && !p.nil?
|
|
||||||
# Nothing to do
|
|
||||||
true
|
|
||||||
elsif p.nil? || (p.active? && move_possible?(p))
|
|
||||||
# Insert the project so that target's children or root projects stay alphabetically sorted
|
|
||||||
sibs = (p.nil? ? self.class.roots : p.children)
|
|
||||||
to_be_inserted_before = sibs.detect {|c| c.name.to_s.downcase > name.to_s.downcase }
|
|
||||||
if to_be_inserted_before
|
|
||||||
move_to_left_of(to_be_inserted_before)
|
|
||||||
elsif p.nil?
|
|
||||||
if sibs.empty?
|
|
||||||
# move_to_root adds the project in first (ie. left) position
|
|
||||||
move_to_root
|
|
||||||
else
|
|
||||||
move_to_right_of(sibs.last) unless self == sibs.last
|
|
||||||
end
|
|
||||||
else
|
|
||||||
# move_to_child_of adds the project in last (ie.right) position
|
|
||||||
move_to_child_of(p)
|
|
||||||
end
|
|
||||||
true
|
|
||||||
else
|
|
||||||
# Can not move to the given target
|
|
||||||
false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns an array of the trackers used by the project and its active sub projects
|
|
||||||
def rolled_up_trackers
|
def rolled_up_trackers
|
||||||
@rolled_up_trackers ||=
|
@rolled_up_trackers ||=
|
||||||
Tracker.find(:all, :include => :projects,
|
Tracker.find(:all, :include => :projects,
|
||||||
:select => "DISTINCT #{Tracker.table_name}.*",
|
:select => "DISTINCT #{Tracker.table_name}.*",
|
||||||
:conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt],
|
:conditions => ["#{Project.table_name}.id = ? OR #{Project.table_name}.parent_id = ?", id, id],
|
||||||
:order => "#{Tracker.table_name}.position")
|
:order => "#{Tracker.table_name}.position")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -270,7 +225,7 @@ class Project < ActiveRecord::Base
|
|||||||
|
|
||||||
# Returns a short description of the projects (first lines)
|
# Returns a short description of the projects (first lines)
|
||||||
def short_description(length = 255)
|
def short_description(length = 255)
|
||||||
description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description
|
description.gsub(/^(.{#{length}}[^\n]*).*$/m, '\1').strip if description
|
||||||
end
|
end
|
||||||
|
|
||||||
def allows_to?(action)
|
def allows_to?(action)
|
||||||
@@ -302,6 +257,8 @@ class Project < ActiveRecord::Base
|
|||||||
|
|
||||||
protected
|
protected
|
||||||
def validate
|
def validate
|
||||||
|
errors.add(parent_id, " must be a root project") if parent and parent.parent
|
||||||
|
errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
|
||||||
errors.add(:identifier, :activerecord_error_invalid) if !identifier.blank? && identifier.match(/^\d*$/)
|
errors.add(:identifier, :activerecord_error_invalid) if !identifier.blank? && identifier.match(/^\d*$/)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
+30
-33
@@ -35,7 +35,7 @@ class QueryCustomFieldColumn < QueryColumn
|
|||||||
|
|
||||||
def initialize(custom_field)
|
def initialize(custom_field)
|
||||||
self.name = "cf_#{custom_field.id}".to_sym
|
self.name = "cf_#{custom_field.id}".to_sym
|
||||||
self.sortable = custom_field.order_statement || false
|
self.sortable = false
|
||||||
@cf = custom_field
|
@cf = custom_field
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -93,15 +93,16 @@ 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'),
|
||||||
QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
|
QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"),
|
||||||
QueryColumn.new(:author),
|
QueryColumn.new(:author),
|
||||||
QueryColumn.new(:assigned_to, :sortable => ["#{User.table_name}.lastname", "#{User.table_name}.firstname"]),
|
QueryColumn.new(:assigned_to, :sortable => "#{User.table_name}.lastname"),
|
||||||
QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
|
QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'),
|
||||||
QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name"),
|
QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name"),
|
||||||
QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc'),
|
QueryColumn.new(:fixed_version, :sortable => "#{Version.table_name}.effective_date", :default_order => 'desc'),
|
||||||
QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
|
QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"),
|
||||||
QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
|
QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"),
|
||||||
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
|
QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"),
|
||||||
@@ -165,10 +166,6 @@ class Query < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
|
@available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty?
|
||||||
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
|
@available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty?
|
||||||
|
|
||||||
if User.current.logged?
|
|
||||||
@available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] }
|
|
||||||
end
|
|
||||||
|
|
||||||
if project
|
if project
|
||||||
# project specific filters
|
# project specific filters
|
||||||
@@ -178,8 +175,8 @@ class Query < ActiveRecord::Base
|
|||||||
unless @project.versions.empty?
|
unless @project.versions.empty?
|
||||||
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
|
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } }
|
||||||
end
|
end
|
||||||
unless @project.descendants.active.empty?
|
unless @project.active_children.empty?
|
||||||
@available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } }
|
@available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } }
|
||||||
end
|
end
|
||||||
add_custom_fields_filters(@project.all_issue_custom_fields)
|
add_custom_fields_filters(@project.all_issue_custom_fields)
|
||||||
else
|
else
|
||||||
@@ -238,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
|
||||||
@@ -261,7 +261,7 @@ class Query < ActiveRecord::Base
|
|||||||
|
|
||||||
def project_statement
|
def project_statement
|
||||||
project_clauses = []
|
project_clauses = []
|
||||||
if project && !@project.descendants.active.empty?
|
if project && !@project.active_children.empty?
|
||||||
ids = [project.id]
|
ids = [project.id]
|
||||||
if has_filter?("subproject_id")
|
if has_filter?("subproject_id")
|
||||||
case operator_for("subproject_id")
|
case operator_for("subproject_id")
|
||||||
@@ -272,10 +272,10 @@ class Query < ActiveRecord::Base
|
|||||||
# main project only
|
# main project only
|
||||||
else
|
else
|
||||||
# all subprojects
|
# all subprojects
|
||||||
ids += project.descendants.collect(&:id)
|
ids += project.child_ids
|
||||||
end
|
end
|
||||||
elsif Setting.display_subprojects_issues?
|
elsif Setting.display_subprojects_issues?
|
||||||
ids += project.descendants.collect(&:id)
|
ids += project.child_ids
|
||||||
end
|
end
|
||||||
project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
|
project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',')
|
||||||
elsif project
|
elsif project
|
||||||
@@ -292,34 +292,31 @@ class Query < ActiveRecord::Base
|
|||||||
next if field == "subproject_id"
|
next if field == "subproject_id"
|
||||||
v = values_for(field).clone
|
v = values_for(field).clone
|
||||||
next unless v and !v.empty?
|
next unless v and !v.empty?
|
||||||
operator = operator_for(field)
|
|
||||||
|
|
||||||
# "me" value subsitution
|
|
||||||
if %w(assigned_to_id author_id watcher_id).include?(field)
|
|
||||||
v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
|
|
||||||
end
|
|
||||||
|
|
||||||
sql = ''
|
sql = ''
|
||||||
|
is_custom_filter = false
|
||||||
if field =~ /^cf_(\d+)$/
|
if field =~ /^cf_(\d+)$/
|
||||||
# custom field
|
# custom field
|
||||||
db_table = CustomValue.table_name
|
db_table = CustomValue.table_name
|
||||||
db_field = 'value'
|
db_field = 'value'
|
||||||
is_custom_filter = true
|
is_custom_filter = true
|
||||||
sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
|
sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
|
||||||
sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')'
|
|
||||||
elsif field == 'watcher_id'
|
|
||||||
db_table = Watcher.table_name
|
|
||||||
db_field = 'user_id'
|
|
||||||
sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND "
|
|
||||||
sql << sql_for_field(field, '=', v, db_table, db_field) + ')'
|
|
||||||
else
|
else
|
||||||
# regular field
|
# regular field
|
||||||
db_table = Issue.table_name
|
db_table = Issue.table_name
|
||||||
db_field = field
|
db_field = field
|
||||||
sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')'
|
sql << '('
|
||||||
end
|
end
|
||||||
filters_clauses << sql
|
|
||||||
|
|
||||||
|
# "me" value subsitution
|
||||||
|
if %w(assigned_to_id author_id).include?(field)
|
||||||
|
v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me")
|
||||||
|
end
|
||||||
|
|
||||||
|
sql = sql + sql_for_field(field, v, db_table, db_field, is_custom_filter)
|
||||||
|
|
||||||
|
sql << ')'
|
||||||
|
filters_clauses << sql
|
||||||
end if filters and valid?
|
end if filters and valid?
|
||||||
|
|
||||||
(filters_clauses << project_statement).join(' AND ')
|
(filters_clauses << project_statement).join(' AND ')
|
||||||
@@ -327,10 +324,10 @@ class Query < ActiveRecord::Base
|
|||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
# Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+
|
# Helper method to generate the WHERE sql for a +field+ with a +value+
|
||||||
def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false)
|
def sql_for_field(field, value, db_table, db_field, is_custom_filter)
|
||||||
sql = ''
|
sql = ''
|
||||||
case operator
|
case operator_for field
|
||||||
when "="
|
when "="
|
||||||
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")"
|
||||||
when "!"
|
when "!"
|
||||||
@@ -371,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
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
# redMine - project management software
|
# redMine - project management software
|
||||||
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
# Copyright (C) 2006-2007 Jean-Philippe Lang
|
||||||
#
|
#
|
||||||
@@ -20,14 +19,14 @@ class Repository < ActiveRecord::Base
|
|||||||
belongs_to :project
|
belongs_to :project
|
||||||
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
|
has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC"
|
||||||
has_many :changes, :through => :changesets
|
has_many :changes, :through => :changesets
|
||||||
|
|
||||||
# Raw SQL to delete changesets and changes in the database
|
# Raw SQL to delete changesets and changes in the database
|
||||||
# has_many :changesets, :dependent => :destroy is too slow for big repositories
|
# has_many :changesets, :dependent => :destroy is too slow for big repositories
|
||||||
before_destroy :clear_changesets
|
before_destroy :clear_changesets
|
||||||
|
|
||||||
# Checks if the SCM is enabled when creating a repository
|
# Checks if the SCM is enabled when creating a repository
|
||||||
validate_on_create { |r| r.errors.add(:type, :activerecord_error_invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
|
validate_on_create { |r| r.errors.add(:type, :activerecord_error_invalid) unless Setting.enabled_scm.include?(r.class.name.demodulize) }
|
||||||
|
|
||||||
# Removes leading and trailing whitespace
|
# Removes leading and trailing whitespace
|
||||||
def url=(arg)
|
def url=(arg)
|
||||||
write_attribute(:url, arg ? arg.to_s.strip : nil)
|
write_attribute(:url, arg ? arg.to_s.strip : nil)
|
||||||
@@ -39,8 +38,7 @@ class Repository < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def scm
|
def scm
|
||||||
init_cache if cache_path.blank? and respond_to?(:init_cache)
|
@scm ||= self.scm_adapter.new url, root_url, login, password
|
||||||
@scm ||= self.scm_adapter.new(url, root_url, login, password, cache_path)
|
|
||||||
update_attribute(:root_url, @scm.root_url) if root_url.blank?
|
update_attribute(:root_url, @scm.root_url) if root_url.blank?
|
||||||
@scm
|
@scm
|
||||||
end
|
end
|
||||||
@@ -78,12 +76,11 @@ class Repository < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
# Default behaviour: we search in cached changesets
|
# Default behaviour: we search in cached changesets
|
||||||
def changesets_for_path(path, options={})
|
def changesets_for_path(path)
|
||||||
path = "/#{path}" unless path.starts_with?('/')
|
path = "/#{path}" unless path.starts_with?('/')
|
||||||
Change.find(:all, :include => {:changeset => :user},
|
Change.find(:all, :include => {:changeset => :user},
|
||||||
:conditions => ["repository_id = ? AND path = ?", id, path],
|
:conditions => ["repository_id = ? AND path = ?", id, path],
|
||||||
:order => "committed_on DESC, #{Changeset.table_name}.id DESC",
|
:order => "committed_on DESC, #{Changeset.table_name}.id DESC").collect(&:changeset)
|
||||||
:limit => options[:limit]).collect(&:changeset)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a path relative to the url of the repository
|
# Returns a path relative to the url of the repository
|
||||||
@@ -164,31 +161,9 @@ class Repository < ActiveRecord::Base
|
|||||||
rescue
|
rescue
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
def remove_cache
|
|
||||||
scm.remove_cache if cache
|
|
||||||
end
|
|
||||||
|
|
||||||
def create_or_sync_cache
|
|
||||||
begin
|
|
||||||
scm.create_cache
|
|
||||||
rescue => e
|
|
||||||
# clean if problem in creation
|
|
||||||
scm.remove_cache
|
|
||||||
end
|
|
||||||
scm.synchronize
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def repositories_cache_directory
|
|
||||||
unless @cache_directory
|
|
||||||
@cache_directory = Setting.repositories_cache_directory.gsub(/^([^#{File::SEPARATOR}].*)/, RAILS_ROOT + '/\1/')
|
|
||||||
Dir.mkdir(@cache_directory, File.umask(0077)) unless File.directory?(@cache_directory)
|
|
||||||
end
|
|
||||||
@cache_directory
|
|
||||||
end
|
|
||||||
|
|
||||||
def before_save
|
def before_save
|
||||||
# Strips url and root_url
|
# Strips url and root_url
|
||||||
url.strip!
|
url.strip!
|
||||||
|
|||||||
@@ -21,17 +21,6 @@ class Repository::Git < Repository
|
|||||||
attr_protected :root_url
|
attr_protected :root_url
|
||||||
validates_presence_of :url
|
validates_presence_of :url
|
||||||
|
|
||||||
before_destroy :remove_cache
|
|
||||||
|
|
||||||
def init_cache
|
|
||||||
return unless dir = repositories_cache_directory
|
|
||||||
# we need to use a cache only if repository isn't local and dir exists
|
|
||||||
if url[/^(rsync|https?|git|ssh):\/\//]
|
|
||||||
update_attribute(:cache_path, dir + project.identifier)
|
|
||||||
update_attribute(:cache, true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def scm_adapter
|
def scm_adapter
|
||||||
Redmine::Scm::Adapters::GitAdapter
|
Redmine::Scm::Adapters::GitAdapter
|
||||||
end
|
end
|
||||||
@@ -40,16 +29,13 @@ class Repository::Git < Repository
|
|||||||
'Git'
|
'Git'
|
||||||
end
|
end
|
||||||
|
|
||||||
def changesets_for_path(path, options={})
|
def changesets_for_path(path)
|
||||||
Change.find(:all, :include => {:changeset => :user},
|
Change.find(:all, :include => {:changeset => :user},
|
||||||
:conditions => ["repository_id = ? AND path = ?", id, path],
|
:conditions => ["repository_id = ? AND path = ?", id, path],
|
||||||
:order => "committed_on DESC, #{Changeset.table_name}.revision DESC",
|
:order => "committed_on DESC, #{Changeset.table_name}.revision DESC").collect(&:changeset)
|
||||||
:limit => options[:limit]).collect(&:changeset)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_changesets
|
def fetch_changesets
|
||||||
create_or_sync_cache if cache
|
|
||||||
|
|
||||||
scm_info = scm.info
|
scm_info = scm.info
|
||||||
if scm_info
|
if scm_info
|
||||||
# latest revision found in database
|
# latest revision found in database
|
||||||
|
|||||||
@@ -21,15 +21,6 @@ class Repository::Mercurial < Repository
|
|||||||
attr_protected :root_url
|
attr_protected :root_url
|
||||||
validates_presence_of :url
|
validates_presence_of :url
|
||||||
|
|
||||||
def init_cache
|
|
||||||
return unless dir = repositories_cache_directory
|
|
||||||
# we need to use a cache only if repository isn't local and dir exists
|
|
||||||
if url[/^(|https?|ssh):\/\//]
|
|
||||||
update_attribute(:cache_path, dir + project.identifier)
|
|
||||||
update_attribute(:cache, true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def scm_adapter
|
def scm_adapter
|
||||||
Redmine::Scm::Adapters::MercurialAdapter
|
Redmine::Scm::Adapters::MercurialAdapter
|
||||||
end
|
end
|
||||||
@@ -62,8 +53,6 @@ class Repository::Mercurial < Repository
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_changesets
|
def fetch_changesets
|
||||||
create_or_sync_cache if cache
|
|
||||||
|
|
||||||
scm_info = scm.info
|
scm_info = scm.info
|
||||||
if scm_info
|
if scm_info
|
||||||
# latest revision found in database
|
# latest revision found in database
|
||||||
|
|||||||
@@ -20,17 +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
|
||||||
|
|
||||||
before_destroy :remove_cache
|
|
||||||
|
|
||||||
def init_cache
|
|
||||||
return unless dir = repositories_cache_directory
|
|
||||||
# we need to use a cache only if repository isn't local and dir exists
|
|
||||||
if cache and url[/^(svn|https?|svn\+ssh):\/\//]
|
|
||||||
update_attribute(:cache_path, dir + project.identifier)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def scm_adapter
|
def scm_adapter
|
||||||
Redmine::Scm::Adapters::SubversionAdapter
|
Redmine::Scm::Adapters::SubversionAdapter
|
||||||
@@ -40,8 +30,8 @@ class Repository::Subversion < Repository
|
|||||||
'Subversion'
|
'Subversion'
|
||||||
end
|
end
|
||||||
|
|
||||||
def changesets_for_path(path, options={})
|
def changesets_for_path(path)
|
||||||
revisions = scm.revisions(path, nil, nil, :limit => options[:limit])
|
revisions = scm.revisions(path)
|
||||||
revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC", :include => :user) : []
|
revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC", :include => :user) : []
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -51,8 +41,6 @@ class Repository::Subversion < Repository
|
|||||||
end
|
end
|
||||||
|
|
||||||
def fetch_changesets
|
def fetch_changesets
|
||||||
create_or_sync_cache if cache
|
|
||||||
|
|
||||||
scm_info = scm.info
|
scm_info = scm.info
|
||||||
if scm_info
|
if scm_info
|
||||||
# latest revision found in database
|
# latest revision found in database
|
||||||
@@ -66,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,
|
||||||
@@ -80,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
|
||||||
|
|||||||
@@ -140,10 +140,6 @@ class Setting < ActiveRecord::Base
|
|||||||
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
|
per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.openid?
|
|
||||||
Object.const_defined?(:OpenID) && self['openid'].to_s == '1'
|
|
||||||
end
|
|
||||||
|
|
||||||
# Checks if settings have changed since the values were read
|
# Checks if settings have changed since the values were read
|
||||||
# and clears the cache hash if it's the case
|
# and clears the cache hash if it's the case
|
||||||
# Called once per request
|
# Called once per request
|
||||||
@@ -165,14 +161,4 @@ private
|
|||||||
setting = find_by_name(name)
|
setting = find_by_name(name)
|
||||||
setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name
|
setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name
|
||||||
end
|
end
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def validate
|
|
||||||
if self.name.to_s == "repositories_cache_directory" and not File.directory?(self.value.to_s)
|
|
||||||
logger.error("Le repertoire #{self.value.to_s} n'existe pas")
|
|
||||||
errors.add("Le repertoire #{self.value.to_s} n'existe pas")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
+5
-4
@@ -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
|
||||||
|
|||||||
+9
-24
@@ -54,7 +54,7 @@ class User < ActiveRecord::Base
|
|||||||
|
|
||||||
validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
|
validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) }
|
||||||
validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
|
validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? }
|
||||||
validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false
|
validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }
|
||||||
# Login must contain lettres, numbers, underscores only
|
# Login must contain lettres, numbers, underscores only
|
||||||
validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
|
validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i
|
||||||
validates_length_of :login, :maximum => 30
|
validates_length_of :login, :maximum => 30
|
||||||
@@ -80,15 +80,6 @@ class User < ActiveRecord::Base
|
|||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
def identity_url=(url)
|
|
||||||
begin
|
|
||||||
self.write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url))
|
|
||||||
rescue InvalidOpenId
|
|
||||||
# Invlaid url, don't save
|
|
||||||
end
|
|
||||||
self.read_attribute(:identity_url)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the user that matches provided login and password, or nil
|
# Returns the user that matches provided login and password, or nil
|
||||||
def self.try_to_login(login, password)
|
def self.try_to_login(login, password)
|
||||||
# Make sure no one can sign in with an empty password
|
# Make sure no one can sign in with an empty password
|
||||||
@@ -147,18 +138,6 @@ class User < ActiveRecord::Base
|
|||||||
def check_password?(clear_password)
|
def check_password?(clear_password)
|
||||||
User.hash_password(clear_password) == self.hashed_password
|
User.hash_password(clear_password) == self.hashed_password
|
||||||
end
|
end
|
||||||
|
|
||||||
# Generate and set a random password. Useful for automated user creation
|
|
||||||
# Based on Token#generate_token_value
|
|
||||||
#
|
|
||||||
def random_password
|
|
||||||
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
|
||||||
password = ''
|
|
||||||
40.times { |i| password << chars[rand(chars.size-1)] }
|
|
||||||
self.password = password
|
|
||||||
self.password_confirmation = password
|
|
||||||
self
|
|
||||||
end
|
|
||||||
|
|
||||||
def pref
|
def pref
|
||||||
self.preference ||= UserPreference.new(:user => self)
|
self.preference ||= UserPreference.new(:user => self)
|
||||||
@@ -196,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
|
||||||
|
|||||||
+4
-40
@@ -51,20 +51,20 @@ class Version < ActiveRecord::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def completed_pourcent
|
def completed_pourcent
|
||||||
if issues_count == 0
|
if fixed_issues.count == 0
|
||||||
0
|
0
|
||||||
elsif open_issues_count == 0
|
elsif open_issues_count == 0
|
||||||
100
|
100
|
||||||
else
|
else
|
||||||
issues_progress(false) + issues_progress(true)
|
(closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def closed_pourcent
|
def closed_pourcent
|
||||||
if issues_count == 0
|
if fixed_issues.count == 0
|
||||||
0
|
0
|
||||||
else
|
else
|
||||||
issues_progress(false)
|
closed_issues_count * 100.0 / fixed_issues.count
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -73,11 +73,6 @@ class Version < ActiveRecord::Base
|
|||||||
effective_date && (effective_date < Date.today) && (open_issues_count > 0)
|
effective_date && (effective_date < Date.today) && (open_issues_count > 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns assigned issues count
|
|
||||||
def issues_count
|
|
||||||
@issue_count ||= fixed_issues.count
|
|
||||||
end
|
|
||||||
|
|
||||||
def open_issues_count
|
def open_issues_count
|
||||||
@open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status)
|
@open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status)
|
||||||
end
|
end
|
||||||
@@ -109,35 +104,4 @@ private
|
|||||||
def check_integrity
|
def check_integrity
|
||||||
raise "Can't delete version" if self.fixed_issues.find(:first)
|
raise "Can't delete version" if self.fixed_issues.find(:first)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns the average estimated time of assigned issues
|
|
||||||
# or 1 if no issue has an estimated time
|
|
||||||
# Used to weigth unestimated issues in progress calculation
|
|
||||||
def estimated_average
|
|
||||||
if @estimated_average.nil?
|
|
||||||
average = fixed_issues.average(:estimated_hours).to_f
|
|
||||||
if average == 0
|
|
||||||
average = 1
|
|
||||||
end
|
|
||||||
@estimated_average = average
|
|
||||||
end
|
|
||||||
@estimated_average
|
|
||||||
end
|
|
||||||
|
|
||||||
# Returns the total progress of open or closed issues
|
|
||||||
def issues_progress(open)
|
|
||||||
@issues_progress ||= {}
|
|
||||||
@issues_progress[open] ||= begin
|
|
||||||
progress = 0
|
|
||||||
if issues_count > 0
|
|
||||||
ratio = open ? 'done_ratio' : 100
|
|
||||||
done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}",
|
|
||||||
:include => :status,
|
|
||||||
:conditions => ["is_closed = ?", !open]).to_f
|
|
||||||
|
|
||||||
progress = done / (estimated_average * issues_count)
|
|
||||||
end
|
|
||||||
progress
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -10,12 +10,6 @@
|
|||||||
<td align="right"><label for="password"><%=l(:field_password)%>:</label></td>
|
<td align="right"><label for="password"><%=l(:field_password)%>:</label></td>
|
||||||
<td align="left"><%= password_field_tag 'password', nil, :size => 40 %></td>
|
<td align="left"><%= password_field_tag 'password', nil, :size => 40 %></td>
|
||||||
</tr>
|
</tr>
|
||||||
<% if Setting.openid? %>
|
|
||||||
<tr>
|
|
||||||
<td align="right"><label for="openid_url"><%=l(:field_identity_url)%></label></td>
|
|
||||||
<td align="left"><%= text_field_tag "openid_url" %></td>
|
|
||||||
</tr>
|
|
||||||
<% end %>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
<td align="left">
|
<td align="left">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<h2><%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url if Setting.openid? %></h2>
|
<h2><%=l(:label_register)%></h2>
|
||||||
|
|
||||||
<% form_tag({:action => 'register'}, :class => "tabular") do %>
|
<% form_tag({:action => 'register'}, :class => "tabular") do %>
|
||||||
<%= error_messages_for 'user' %>
|
<%= error_messages_for 'user' %>
|
||||||
@@ -29,12 +29,7 @@
|
|||||||
<p><label for="user_language"><%=l(:field_language)%></label>
|
<p><label for="user_language"><%=l(:field_language)%></label>
|
||||||
<%= select("user", "language", lang_options_for_select) %></p>
|
<%= select("user", "language", lang_options_for_select) %></p>
|
||||||
|
|
||||||
<% if Setting.openid? %>
|
<% @user.custom_field_values.each do |value| %>
|
||||||
<p><label for="user_identity_url"><%=l(:field_identity_url)%></label>
|
|
||||||
<%= text_field 'user', 'identity_url' %></p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %>
|
|
||||||
<p><%= custom_field_tag_with_label :user, value %></p>
|
<p><%= custom_field_tag_with_label :user, value %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<!--[eoform:user]-->
|
<!--[eoform:user]-->
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
|
<li><%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% for custom_value in @custom_values %>
|
<% for custom_value in @custom_values %>
|
||||||
<% if !custom_value.value.empty? %>
|
<% if !custom_value.value.blank? %>
|
||||||
<li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
|
<li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
@@ -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">
|
||||||
@@ -55,14 +56,16 @@
|
|||||||
<% end -%>
|
<% end -%>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %>
|
<%= l(:label_export_to) %>
|
||||||
<% end %>
|
<%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key}, :class => 'feed' %>
|
||||||
|
</p>
|
||||||
|
|
||||||
<% content_for :header_tags do %>
|
<% content_for :header_tags do %>
|
||||||
<%= 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 %>
|
||||||
|
|||||||
@@ -17,20 +17,22 @@
|
|||||||
|
|
||||||
<table class="list">
|
<table class="list">
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
<th><%=l(:label_project)%></th>
|
<%= sort_header_tag('name', :caption => l(:label_project)) %>
|
||||||
<th><%=l(:field_description)%></th>
|
<th><%=l(:field_description)%></th>
|
||||||
<th><%=l(:field_is_public)%></th>
|
<th><%=l(:label_subproject_plural)%></th>
|
||||||
<th><%=l(:field_created_on)%></th>
|
<%= sort_header_tag('is_public', :caption => l(:field_is_public), :default_order => 'desc') %>
|
||||||
|
<%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %>
|
||||||
<th></th>
|
<th></th>
|
||||||
<th></th>
|
<th></th>
|
||||||
</tr></thead>
|
</tr></thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<% for project in @projects %>
|
<% for project in @projects %>
|
||||||
<tr class="<%= cycle("odd", "even") %> <%= css_project_classes(project) %>">
|
<tr class="<%= cycle("odd", "even") %>">
|
||||||
<td class="name" style="padding-left: <%= project.level %>em;"><%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %></td>
|
<td><%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %>
|
||||||
<td><%= textilizable project.short_description, :project => project %></td>
|
<td><%= textilizable project.short_description, :project => project %>
|
||||||
<td align="center"><%= image_tag 'true.png' if project.is_public? %></td>
|
<td align="center"><%= project.children.size %>
|
||||||
<td align="center"><%= format_date(project.created_on) %></td>
|
<td align="center"><%= image_tag 'true.png' if project.is_public? %>
|
||||||
|
<td align="center"><%= format_date(project.created_on) %>
|
||||||
<td align="center" style="width:10%">
|
<td align="center" style="width:10%">
|
||||||
<small>
|
<small>
|
||||||
<%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>
|
<%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %>
|
||||||
@@ -45,4 +47,6 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
<p class="pagination"><%= pagination_links_full @project_pages, @project_count %></p>
|
||||||
|
|
||||||
<% html_title(l(:label_project_plural)) -%>
|
<% html_title(l(:label_project_plural)) -%>
|
||||||
|
|||||||
@@ -29,9 +29,11 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_messages => 1, :key => User.current.rss_key} %>
|
<%= l(:label_export_to) %>
|
||||||
<% end %>
|
<span><%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key},
|
||||||
|
:class => 'feed' %></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
<% content_for :header_tags do %>
|
<% content_for :header_tags do %>
|
||||||
<%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %>
|
<%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %>
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
<%= link_to_if_authorized l(:label_message_new),
|
<%= link_to_if_authorized l(:label_message_new),
|
||||||
{:controller => 'messages', :action => 'new', :board_id => @board},
|
{:controller => 'messages', :action => 'new', :board_id => @board},
|
||||||
:class => 'icon icon-add',
|
:class => 'icon icon-add',
|
||||||
:onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %>
|
:onclick => 'Element.show("add-message"); return false;' %>
|
||||||
<%= watcher_tag(@board, User.current) %>
|
<%= watcher_tag(@board, User.current) %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -49,6 +49,23 @@ function toggle_custom_field_format() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addValueField() {
|
||||||
|
var f = $$('p#custom_field_possible_values span');
|
||||||
|
p = document.getElementById("custom_field_possible_values");
|
||||||
|
var v = f[0].cloneNode(true);
|
||||||
|
v.childNodes[0].value = "";
|
||||||
|
p.appendChild(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteValueField(e) {
|
||||||
|
var f = $$('p#custom_field_possible_values span');
|
||||||
|
if (f.length == 1) {
|
||||||
|
e.parentNode.childNodes[0].value = "";
|
||||||
|
} else {
|
||||||
|
Element.remove(e.parentNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//]]>
|
//]]>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -59,22 +76,23 @@ function toggle_custom_field_format() {
|
|||||||
<%= f.text_field :min_length, :size => 5, :no_label => true %> -
|
<%= f.text_field :min_length, :size => 5, :no_label => true %> -
|
||||||
<%= f.text_field :max_length, :size => 5, :no_label => true %><br>(<%=l(:text_min_max_length_info)%>)</p>
|
<%= f.text_field :max_length, :size => 5, :no_label => true %><br>(<%=l(:text_min_max_length_info)%>)</p>
|
||||||
<p><%= f.text_field :regexp, :size => 50 %><br>(<%=l(:text_regexp_info)%>)</p>
|
<p><%= f.text_field :regexp, :size => 50 %><br>(<%=l(:text_regexp_info)%>)</p>
|
||||||
<p id="custom_field_possible_values"><%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"),
|
<p id="custom_field_possible_values"><label><%= l(:field_possible_values) %> <%= image_to_function "add.png", "addValueField();return false" %></label>
|
||||||
:cols => 20,
|
<% (@custom_field.possible_values.to_a + [""]).each do |value| %>
|
||||||
:rows => 15 %>
|
<span><%= text_field_tag 'custom_field[possible_values][]', value, :size => 30 %> <%= image_to_function "delete.png", "deleteValueField(this);return false" %><br /></span>
|
||||||
<br /><em><%= l(:text_custom_field_possible_values_info) %></em></p>
|
<% end %>
|
||||||
|
</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">
|
||||||
<% case @custom_field.class.name
|
<% case @custom_field.type.to_s
|
||||||
when "IssueCustomField" %>
|
when "IssueCustomField" %>
|
||||||
|
|
||||||
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
|
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
|
||||||
<% for tracker in @trackers %>
|
<% for tracker in @trackers %>
|
||||||
<%= check_box_tag "custom_field[tracker_ids][]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %>
|
<%= check_box_tag "tracker_ids[]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= hidden_field_tag "custom_field[tracker_ids][]", '' %>
|
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<p><%= f.check_box :is_required %></p>
|
<p><%= f.check_box :is_required %></p>
|
||||||
@@ -84,7 +102,6 @@ when "IssueCustomField" %>
|
|||||||
|
|
||||||
<% when "UserCustomField" %>
|
<% when "UserCustomField" %>
|
||||||
<p><%= f.check_box :is_required %></p>
|
<p><%= f.check_box :is_required %></p>
|
||||||
<p><%= f.check_box :editable %></p>
|
|
||||||
|
|
||||||
<% when "ProjectCustomField" %>
|
<% when "ProjectCustomField" %>
|
||||||
<p><%= f.check_box :is_required %></p>
|
<p><%= f.check_box :is_required %></p>
|
||||||
@@ -93,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();" %>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<%= link_to_if_authorized l(:label_document_new),
|
<%= link_to_if_authorized l(:label_document_new),
|
||||||
{:controller => 'documents', :action => 'new', :project_id => @project},
|
{:controller => 'documents', :action => 'new', :project_id => @project},
|
||||||
:class => 'icon icon-add',
|
:class => 'icon icon-add',
|
||||||
:onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %>
|
:onclick => 'Element.show("add-document"); return false;' %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="add-document" style="display:none;">
|
<div id="add-document" style="display:none;">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
:class => 'wiki-edit' %></p>
|
:class => 'wiki-edit' %></p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="attributes">
|
|
||||||
<div class="splitcontentleft">
|
<div class="splitcontentleft">
|
||||||
<% if @issue.new_record? || @allowed_statuses.any? %>
|
<% if @issue.new_record? || @allowed_statuses.any? %>
|
||||||
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
|
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
|
||||||
@@ -29,7 +28,7 @@
|
|||||||
<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, :authenticity_token => form_authenticity_token},
|
||||||
: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 %>
|
<% end %>
|
||||||
<%= content_tag('p', f.select(:fixed_version_id,
|
<%= content_tag('p', f.select(:fixed_version_id,
|
||||||
@@ -46,7 +45,6 @@
|
|||||||
|
|
||||||
<div style="clear:both;"> </div>
|
<div style="clear:both;"> </div>
|
||||||
<%= render :partial => 'form_custom_fields' %>
|
<%= render :partial => 'form_custom_fields' %>
|
||||||
</div>
|
|
||||||
|
|
||||||
<% if @issue.new_record? %>
|
<% if @issue.new_record? %>
|
||||||
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
|
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
<div class="attributes">
|
|
||||||
<div class="splitcontentleft">
|
<div class="splitcontentleft">
|
||||||
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
|
<p><%= f.select :status_id, (@allowed_statuses.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>
|
||||||
@@ -9,4 +8,3 @@
|
|||||||
(@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? %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
<table class="list issues">
|
<table class="list issues">
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
<th>#</th>
|
<th>#</th>
|
||||||
<th><%=l(:field_project)%></th>
|
|
||||||
<th><%=l(:field_tracker)%></th>
|
<th><%=l(:field_tracker)%></th>
|
||||||
<th><%=l(:field_subject)%></th>
|
<th><%=l(:field_subject)%></th>
|
||||||
</tr></thead>
|
</tr></thead>
|
||||||
@@ -11,14 +10,14 @@
|
|||||||
<% for issue in issues %>
|
<% for issue in issues %>
|
||||||
<tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= css_issue_classes(issue) %>">
|
<tr id="issue-<%= issue.id %>" class="hascontextmenu <%= cycle('odd', 'even') %> <%= css_issue_classes(issue) %>">
|
||||||
<td class="id">
|
<td class="id">
|
||||||
<%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %>
|
<%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %>
|
||||||
<%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
|
<%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
|
||||||
</td>
|
</td>
|
||||||
<td class="project"><%=h issue.project %></td>
|
<td><%=h issue.project.name %> - <%= issue.tracker.name %><br />
|
||||||
<td class="tracker"><%=h issue.tracker %></td>
|
<%= issue.status.name %> - <%= format_time(issue.updated_on) %></td>
|
||||||
<td class="subject">
|
<td class="subject">
|
||||||
<%= link_to h(truncate(issue.subject, 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>)
|
<%= link_to h(issue.subject), :controller => 'issues', :action => 'show', :id => issue %>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<% end %>
|
<% end %>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
<% if @issue.relations.any? %>
|
<% if @issue.relations.any? %>
|
||||||
<table style="width:100%">
|
<table style="width:100%">
|
||||||
<% @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation| %>
|
<% @issue.relations.each do |relation| %>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%= l(relation.label_for(@issue)) %> <%= "(#{lwr(:actionview_datehelper_time_in_words_day, relation.delay)})" if relation.delay && relation.delay != 0 %>
|
<td><%= l(relation.label_for(@issue)) %> <%= "(#{lwr(:actionview_datehelper_time_in_words_day, relation.delay)})" if relation.delay && relation.delay != 0 %>
|
||||||
<%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %> <%= link_to_issue relation.other_issue(@issue) %></td>
|
<%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %> <%= link_to_issue relation.other_issue(@issue) %></td>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
<label><%= l(:field_fixed_version) %>:
|
<label><%= l(:field_fixed_version) %>:
|
||||||
<%= select_tag('fixed_version_id', content_tag('option', l(:label_no_change_option), :value => '') +
|
<%= select_tag('fixed_version_id', content_tag('option', l(:label_no_change_option), :value => '') +
|
||||||
content_tag('option', l(:label_none), :value => 'none') +
|
content_tag('option', l(:label_none), :value => 'none') +
|
||||||
options_from_collection_for_select(@project.versions.sort, :id, :name)) %></label>
|
options_from_collection_for_select(@project.versions, :id, :name)) %></label>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@@ -38,13 +38,6 @@
|
|||||||
<label><%= l(:field_done_ratio) %>:
|
<label><%= l(:field_done_ratio) %>:
|
||||||
<%= select_tag 'done_ratio', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></label>
|
<%= select_tag 'done_ratio', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></label>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<% @custom_fields.each do |custom_field| %>
|
|
||||||
<p><label><%= h(custom_field.name) %></label>
|
|
||||||
<%= select_tag "custom_field_values[#{custom_field.id}]", options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values) %></label>
|
|
||||||
</p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
|
<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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>
|
||||||
@@ -79,10 +81,7 @@
|
|||||||
:class => 'icon-copy', :disabled => !@can[:copy] %></li>
|
:class => 'icon-copy', :disabled => !@can[:copy] %></li>
|
||||||
<% if @can[:log_time] -%>
|
<% if @can[:log_time] -%>
|
||||||
<li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},
|
<li><%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue},
|
||||||
:class => 'icon-time-add' %></li>
|
:class => 'icon-time' %></li>
|
||||||
<% end %>
|
|
||||||
<% if User.current.logged? %>
|
|
||||||
<li><%= watcher_link(@issue, User.current) %></li>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
@@ -90,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>
|
||||||
|
|||||||
@@ -241,10 +241,13 @@ if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'PDF', :url => @gantt.params %>
|
<%= l(:label_export_to) %>
|
||||||
<%= f.link_to('PNG', :url => @gantt.params) if @gantt.respond_to?('to_image') %>
|
<span><%= link_to 'PDF', @gantt.params.merge(:format => 'pdf'), :class => 'pdf' %></span>
|
||||||
|
<% if @gantt.respond_to?('to_image') %>
|
||||||
|
<span><%= link_to 'PNG', @gantt.params.merge(:format => 'png'), :class => 'image' %></span>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
</p>
|
||||||
<% end # query.valid? %>
|
<% end # query.valid? %>
|
||||||
|
|
||||||
<% content_for :sidebar do %>
|
<% content_for :sidebar do %>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<% html_title(l(:label_issue_plural)) %>
|
<% html_title(l(:label_issue_plural)) %>
|
||||||
|
|
||||||
<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
|
<% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %>
|
||||||
<%= hidden_field_tag('project_id', @project.to_param) if @project %>
|
<%= hidden_field_tag('project_id', @project.id) if @project %>
|
||||||
<fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
|
<fieldset id="filters"><legend><%= l(:label_filter_plural) %></legend>
|
||||||
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
|
<%= render :partial => 'queries/filters', :locals => {:query => @query} %>
|
||||||
<p class="buttons">
|
<p class="buttons">
|
||||||
@@ -14,8 +14,7 @@
|
|||||||
}, :class => 'icon icon-checked' %>
|
}, :class => 'icon icon-checked' %>
|
||||||
|
|
||||||
<%= link_to_remote l(:button_clear),
|
<%= link_to_remote l(:button_clear),
|
||||||
{ :url => { :set_filter => 1, :project_id => @project },
|
{ :url => { :set_filter => 1 },
|
||||||
:method => :get,
|
|
||||||
:update => "content",
|
:update => "content",
|
||||||
}, :class => 'icon icon-reload' %>
|
}, :class => 'icon icon-reload' %>
|
||||||
|
|
||||||
@@ -43,14 +42,14 @@
|
|||||||
<% 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>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
|
||||||
<%= f.link_to 'Atom', :url => {:query_id => (@query.new_record? ? nil : @query), :key => User.current.rss_key} %>
|
|
||||||
<%= f.link_to 'CSV' %>
|
|
||||||
<%= f.link_to 'PDF' %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% end %>
|
<p class="other-formats">
|
||||||
|
<%= l(:label_export_to) %>
|
||||||
|
<span><%= link_to 'Atom', {:query_id => @query, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
|
||||||
|
<span><%= link_to 'CSV', {:format => 'csv'}, :class => 'csv' %></span>
|
||||||
|
<span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
|
||||||
|
</p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% content_for :sidebar do %>
|
<% content_for :sidebar do %>
|
||||||
|
|||||||
@@ -6,19 +6,16 @@
|
|||||||
<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
|
<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
|
||||||
|
|
||||||
<div class="box tabular">
|
<div class="box tabular">
|
||||||
<p><label for="new_project_id"><%=l(:field_project)%>:</label>
|
<p><label for="new_project_id"><%=l(:field_project)%> :</label>
|
||||||
<%= select_tag "new_project_id",
|
<%= select_tag "new_project_id",
|
||||||
project_tree_options_for_select(@allowed_projects, :selected => @target_project),
|
options_from_collection_for_select(@allowed_projects, 'id', 'name', @target_project.id),
|
||||||
:onchange => remote_function(:url => { :action => 'move' },
|
:onchange => remote_function(:url => { :action => 'move' },
|
||||||
:method => :get,
|
:method => :get,
|
||||||
:update => 'content',
|
:update => 'content',
|
||||||
:with => "Form.serialize('move_form')") %></p>
|
:with => "Form.serialize('move_form')") %></p>
|
||||||
|
|
||||||
<p><label for="new_tracker_id"><%=l(:field_tracker)%>:</label>
|
<p><label for="new_tracker_id"><%=l(:field_tracker)%> :</label>
|
||||||
<%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
|
<%= select_tag "new_tracker_id", "<option value=\"\">#{l(:label_no_change_option)}</option>" + options_from_collection_for_select(@trackers, "id", "name") %></p>
|
||||||
|
|
||||||
<p><label for="copy_options_copy"><%= l(:button_copy)%></label>
|
|
||||||
<%= check_box_tag "copy_options[copy]", "1" %></p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= submit_tag l(:button_move) %>
|
<%= submit_tag l(:button_move) %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div class="contextual">
|
<div class="contextual">
|
||||||
<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
|
<%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %>
|
||||||
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time-add' %>
|
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %>
|
||||||
<%= watcher_tag(@issue, User.current) %>
|
<%= watcher_tag(@issue, User.current) %>
|
||||||
<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
|
<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %>
|
||||||
<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %>
|
<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %>
|
||||||
@@ -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,7 +19,7 @@
|
|||||||
|
|
||||||
<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>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
|
<td class="category"><b><%=l(:field_category)%>:</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>
|
||||||
<% if User.current.allowed_to?(:view_time_entries, @project) %>
|
<% if User.current.allowed_to?(:view_time_entries, @project) %>
|
||||||
<td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
|
<td class="spent-time"><b><%=l(:label_spent_time)%>:</b></td>
|
||||||
<td class="spent-hours"><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %></td>
|
<td class="spent-hours"><%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %></td>
|
||||||
<% end %>
|
<% end %>
|
||||||
</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)
|
||||||
@@ -69,6 +69,8 @@ end %>
|
|||||||
|
|
||||||
<%= link_to_attachments @issue %>
|
<%= link_to_attachments @issue %>
|
||||||
|
|
||||||
|
<%= 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 />
|
||||||
<div id="relations">
|
<div id="relations">
|
||||||
@@ -108,10 +110,11 @@ end %>
|
|||||||
</div>
|
</div>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %>
|
<%= l(:label_export_to) %>
|
||||||
<%= f.link_to 'PDF' %>
|
<span><%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
|
||||||
<% end %>
|
<span><%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
|
<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %>
|
<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %>
|
||||||
<%= text_area_tag :notes, h(@journal.notes), :class => 'wiki-edit',
|
<%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit',
|
||||||
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
|
:rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %>
|
||||||
<%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>
|
<%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>
|
||||||
<p><%= submit_tag l(:button_save) %>
|
<p><%= submit_tag l(:button_save) %>
|
||||||
<%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " +
|
<%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " +
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
<% user_projects_by_root = User.current.projects.find(:all, :include => :parent).group_by(&:root) %>
|
||||||
|
<select onchange="if (this.value != '') { window.location = this.value; }">
|
||||||
|
<option selected="selected"><%= l(:label_jump_to_a_project) %></option>
|
||||||
|
<option disabled="disabled">---</option>
|
||||||
|
<% user_projects_by_root.keys.sort.each do |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| %>
|
||||||
|
<% next if project == root %>
|
||||||
|
<%= content_tag('option', ('» ' + h(project.name)), :value => url_for(:controller => 'projects', :action => 'show', :id => project, :jump => current_menu_item)) %>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</select>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project}, :accesskey => accesskey(:search) %>:
|
<%= link_to l(:label_search), {:controller => 'search', :action => 'index', :id => @project}, :accesskey => accesskey(:search) %>:
|
||||||
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
|
<%= text_field_tag 'q', @question, :size => 20, :class => 'small', :accesskey => accesskey(:quick_search) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
<%= render_project_jump_box %>
|
<%= render :partial => 'layouts/project_selector' if User.current.memberships.any? %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1><%= h(@project && !@project.new_record? ? @project.name : Setting.app_title) %></h1>
|
<h1><%= h(@project && !@project.new_record? ? @project.name : Setting.app_title) %></h1>
|
||||||
|
|||||||
@@ -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,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,3 +1,3 @@
|
|||||||
<%= yield %>
|
<%= yield %>
|
||||||
----------------------------------------
|
--
|
||||||
<%= Setting.emails_footer %>
|
<%= Setting.emails_footer %>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@
|
|||||||
<h3 class="icon22 icon22-comment"><%= l(:label_reply_plural) %></h3>
|
<h3 class="icon22 icon22-comment"><%= l(:label_reply_plural) %></h3>
|
||||||
<% @replies.each do |message| %>
|
<% @replies.each do |message| %>
|
||||||
<a name="<%= "message-#{message.id}" %>"></a>
|
<a name="<%= "message-#{message.id}" %>"></a>
|
||||||
|
<div class="contextual">
|
||||||
|
<%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>
|
||||||
|
<%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>
|
||||||
|
<%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>
|
||||||
|
</div>
|
||||||
<div class="message reply">
|
<div class="message reply">
|
||||||
<div class="contextual">
|
|
||||||
<%= link_to_remote_if_authorized image_tag('comment.png'), { :url => {:action => 'quote', :id => message} }, :title => l(:button_quote) %>
|
|
||||||
<%= link_to(image_tag('edit.png'), {:action => 'edit', :id => message}, :title => l(:button_edit)) if message.editable_by?(User.current) %>
|
|
||||||
<%= link_to(image_tag('delete.png'), {:action => 'destroy', :id => message}, :method => :post, :confirm => l(:text_are_you_sure), :title => l(:button_delete)) if message.destroyable_by?(User.current) %>
|
|
||||||
</div>
|
|
||||||
<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, :author => false %>
|
<%= link_to_attachments message, :author => false %>
|
||||||
|
|||||||
@@ -15,13 +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>
|
||||||
<% if Setting.openid? %>
|
<%= call_hook(:view_my_account, :user => @user, :form => f) %>
|
||||||
<p><%= f.text_field :identity_url %></p>
|
|
||||||
<% end %>
|
|
||||||
|
|
||||||
<% @user.custom_field_values.select(&:editable?).each do |value| %>
|
|
||||||
<p><%= custom_field_tag_with_label :user, value %></p>
|
|
||||||
<% end %>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<h3><%=l(:label_assigned_to_me_issues)%></h3>
|
<h3><%=l(:label_assigned_to_me_issues)%></h3>
|
||||||
<% assigned_issues = Issue.visible.find(:all,
|
<% assigned_issues = Issue.find(:all,
|
||||||
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=?", user.id, false],
|
:conditions => ["assigned_to_id=? AND #{IssueStatus.table_name}.is_closed=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id, false],
|
||||||
:limit => 10,
|
:limit => 10,
|
||||||
:include => [ :status, :project, :tracker, :priority ],
|
:include => [ :status, :project, :tracker, :priority ],
|
||||||
:order => "#{Enumeration.table_name}.position DESC, #{Issue.table_name}.updated_on DESC") %>
|
:order => "#{Enumeration.table_name}.position DESC, #{Issue.table_name}.updated_on DESC") %>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<h3><%=l(:label_reported_issues)%></h3>
|
<h3><%=l(:label_reported_issues)%></h3>
|
||||||
<% reported_issues = Issue.visible.find(:all,
|
<% reported_issues = Issue.find(:all,
|
||||||
:conditions => { :author_id => user.id },
|
:conditions => ["author_id=? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
|
||||||
:limit => 10,
|
:limit => 10,
|
||||||
:include => [ :status, :project, :tracker ],
|
:include => [ :status, :project, :tracker ],
|
||||||
:order => "#{Issue.table_name}.updated_on DESC") %>
|
:order => "#{Issue.table_name}.updated_on DESC") %>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<h3><%=l(:label_watched_issues)%></h3>
|
<h3><%=l(:label_watched_issues)%></h3>
|
||||||
<% watched_issues = Issue.visible.find(:all,
|
<% watched_issues = Issue.find(:all,
|
||||||
:include => [:status, :project, :tracker, :watchers],
|
:include => [:status, :project, :tracker, :watchers],
|
||||||
:limit => 10,
|
:limit => 10,
|
||||||
:conditions => ["#{Watcher.table_name}.user_id = ?", user.id],
|
:conditions => ["#{Watcher.table_name}.user_id = ? AND #{Project.table_name}.status=#{Project::STATUS_ACTIVE}", user.id],
|
||||||
:order => "#{Issue.table_name}.updated_on DESC") %>
|
:order => "#{Issue.table_name}.updated_on DESC") %>
|
||||||
<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %>
|
<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %>
|
||||||
<% if watched_issues.length > 0 %>
|
<% if watched_issues.length > 0 %>
|
||||||
<p class="small"><%= link_to l(:label_issue_view_all), :controller => 'issues', :action => 'index', :set_filter => 1, :watcher_id => 'me' %></p>
|
<p><%=lwr(:label_last_updates, watched_issues.length)%></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<%= link_to_if_authorized(l(:label_news_new),
|
<%= link_to_if_authorized(l(:label_news_new),
|
||||||
{:controller => 'news', :action => 'new', :project_id => @project},
|
{:controller => 'news', :action => 'new', :project_id => @project},
|
||||||
:class => 'icon icon-add',
|
:class => 'icon icon-add',
|
||||||
:onclick => 'Element.show("add-news"); Form.Element.focus("news_title"); return false;') if @project %>
|
:onclick => 'Element.show("add-news"); return false;') if @project %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="add-news" style="display:none;">
|
<div id="add-news" style="display:none;">
|
||||||
@@ -39,9 +39,10 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
<p class="pagination"><%= pagination_links_full @news_pages %></p>
|
<p class="pagination"><%= pagination_links_full @news_pages %></p>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %>
|
<%= l(:label_export_to) %>
|
||||||
<% end %>
|
<span><%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %></span>
|
||||||
|
</p>
|
||||||
|
|
||||||
<% content_for :header_tags do %>
|
<% content_for :header_tags do %>
|
||||||
<%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %>
|
<%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %>
|
||||||
|
|||||||
@@ -48,10 +48,8 @@
|
|||||||
<% if authorize_for 'news', 'add_comment' %>
|
<% if authorize_for 'news', 'add_comment' %>
|
||||||
<p><%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %></p>
|
<p><%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %></p>
|
||||||
<% form_tag({:action => 'add_comment', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %>
|
<% form_tag({:action => 'add_comment', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %>
|
||||||
<div class="box">
|
<%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %>
|
||||||
<%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %>
|
<%= wikitoolbar_for 'comment_comments' %>
|
||||||
<%= wikitoolbar_for 'comment_comments' %>
|
|
||||||
</div>
|
|
||||||
<p><%= submit_tag l(:button_add) %></p>
|
<p><%= submit_tag l(:button_add) %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
<!--[form:project]-->
|
<!--[form:project]-->
|
||||||
<p><%= f.text_field :name, :required => true %><br /><em><%= l(:text_caracters_maximum, 30) %></em></p>
|
<p><%= f.text_field :name, :required => true %><br /><em><%= l(:text_caracters_maximum, 30) %></em></p>
|
||||||
|
|
||||||
<% if User.current.admin? && !@project.possible_parents.empty? %>
|
<% if User.current.admin? and !@root_projects.empty? %>
|
||||||
<p><label><%= l(:field_parent) %></label><%= parent_project_select_tag(@project) %></p>
|
<p><%= f.select :parent_id, (@root_projects.collect {|p| [p.name, p.id]}), { :include_blank => true } %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<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, 2, 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>
|
||||||
|
|||||||
@@ -22,20 +22,21 @@
|
|||||||
|
|
||||||
<div style="float:left;">
|
<div style="float:left;">
|
||||||
<%= link_to_remote(('« ' + l(:label_previous)),
|
<%= link_to_remote(('« ' + l(:label_previous)),
|
||||||
{:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
|
{:update => "content", :url => params.merge(:from => @date_to - @days - 1), :complete => 'window.scrollTo(0,0)'},
|
||||||
{:href => url_for(params.merge(:from => @date_to - @days - 1)),
|
{:href => url_for(params.merge(:from => @date_to - @days - 1)),
|
||||||
:title => "#{l(:label_date_from)} #{format_date(@date_to - 2*@days)} #{l(:label_date_to).downcase} #{format_date(@date_to - @days - 1)}"}) %>
|
:title => "#{l(:label_date_from)} #{format_date(@date_to - 2*@days)} #{l(:label_date_to).downcase} #{format_date(@date_to - @days - 1)}"}) %>
|
||||||
</div>
|
</div>
|
||||||
<div style="float:right;">
|
<div style="float:right;">
|
||||||
<%= link_to_remote((l(:label_next) + ' »'),
|
<%= link_to_remote((l(:label_next) + ' »'),
|
||||||
{:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'},
|
{:update => "content", :url => params.merge(:from => @date_to + @days - 1), :complete => 'window.scrollTo(0,0)'},
|
||||||
{:href => url_for(params.merge(:from => @date_to + @days - 1)),
|
{:href => url_for(params.merge(:from => @date_to + @days - 1)),
|
||||||
:title => "#{l(:label_date_from)} #{format_date(@date_to)} #{l(:label_date_to).downcase} #{format_date(@date_to + @days - 1)}"}) unless @date_to >= Date.today %>
|
:title => "#{l(:label_date_from)} #{format_date(@date_to)} #{l(:label_date_to).downcase} #{format_date(@date_to + @days - 1)}"}) unless @date_to >= Date.today %>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<% other_formats_links do |f| %>
|
<p class="other-formats">
|
||||||
<%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %>
|
<%= l(:label_export_to) %>
|
||||||
<% end %>
|
<%= link_to 'Atom', params.merge(:format => :atom, :from => nil, :key => User.current.rss_key), :class => 'feed' %>
|
||||||
|
</p>
|
||||||
|
|
||||||
<% content_for :header_tags do %>
|
<% content_for :header_tags do %>
|
||||||
<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %>
|
<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %>
|
||||||
@@ -45,9 +46,11 @@
|
|||||||
<% 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.descendants.active.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>
|
||||||
<%= hidden_field_tag 'with_subprojects', 0 %>
|
<%= hidden_field_tag 'with_subprojects', 0 %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -13,5 +13,4 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<%= submit_tag l(:button_save) %>
|
<%= submit_tag l(:button_save) %>
|
||||||
<%= javascript_tag "Form.Element.focus('project_name');" %>
|
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
<% content_for :sidebar do %>
|
<% content_for :sidebar do %>
|
||||||
<% form_tag({},:method => :get) do %>
|
<% form_tag do %>
|
||||||
<h3><%= l(:label_change_log) %></h3>
|
<h3><%= l(:label_change_log) %></h3>
|
||||||
<% @trackers.each do |tracker| %>
|
<% @trackers.each do |tracker| %>
|
||||||
<label><%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
|
<label><%= check_box_tag "tracker_ids[]", tracker.id, (@selected_tracker_ids.include? tracker.id.to_s) %>
|
||||||
|
|||||||
@@ -3,8 +3,8 @@
|
|||||||
<p><strong><%=h @project_to_destroy %></strong><br />
|
<p><strong><%=h @project_to_destroy %></strong><br />
|
||||||
<%=l(:text_project_destroy_confirmation)%>
|
<%=l(:text_project_destroy_confirmation)%>
|
||||||
|
|
||||||
<% if @project_to_destroy.descendants.any? %>
|
<% if @project_to_destroy.children.any? %>
|
||||||
<br /><%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.descendants.collect{|p| p.to_s}.join(', ')))) %>
|
<br /><%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.children.sort.collect{|p| p.to_s}.join(', ')))) %>
|
||||||
<% end %>
|
<% end %>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user