0.3 unstable

git-svn-id: http://redmine.rubyforge.org/svn/trunk@12 e93f8b46-1217-0410-a6f0-8f06a7374b81
pull/351/head
Jean-Philippe Lang 19 years ago
parent 7e57db1edb
commit 310a0f924a
  1. 141
      redmine/app/controllers/account_controller.rb
  2. 63
      redmine/app/controllers/application.rb
  3. 82
      redmine/app/controllers/auth_sources_controller.rb
  4. 57
      redmine/app/controllers/custom_fields_controller.rb
  5. 2
      redmine/app/controllers/documents_controller.rb
  6. 44
      redmine/app/controllers/issues_controller.rb
  7. 230
      redmine/app/controllers/projects_controller.rb
  8. 15
      redmine/app/controllers/users_controller.rb
  9. 9
      redmine/app/controllers/welcome_controller.rb
  10. 78
      redmine/app/helpers/application_helper.rb
  11. 19
      redmine/app/helpers/auth_sources_helper.rb
  12. 62
      redmine/app/helpers/custom_fields_helper.rb
  13. 2
      redmine/app/models/attachment.rb
  14. 47
      redmine/app/models/auth_source.rb
  15. 79
      redmine/app/models/auth_source_ldap.rb
  16. 38
      redmine/app/models/custom_field.rb
  17. 42
      redmine/app/models/custom_value.rb
  18. 2
      redmine/app/models/document.rb
  19. 12
      redmine/app/models/issue.rb
  20. 27
      redmine/app/models/issue_custom_field.rb
  21. 46
      redmine/app/models/mailer.rb
  22. 2
      redmine/app/models/news.rb
  23. 2
      redmine/app/models/permission.rb
  24. 52
      redmine/app/models/project.rb
  25. 22
      redmine/app/models/project_custom_field.rb
  26. 44
      redmine/app/models/token.rb
  27. 3
      redmine/app/models/tracker.rb
  28. 49
      redmine/app/models/user.rb
  29. 23
      redmine/app/models/user_custom_field.rb
  30. 34
      redmine/app/views/account/login.rhtml
  31. 14
      redmine/app/views/account/lost_password.rhtml
  32. 36
      redmine/app/views/account/my_account.rhtml
  33. 17
      redmine/app/views/account/my_page.rhtml
  34. 21
      redmine/app/views/account/password_recovery.rhtml
  35. 46
      redmine/app/views/account/register.rhtml
  36. 8
      redmine/app/views/account/show.rhtml
  37. 31
      redmine/app/views/admin/index.rhtml
  38. 4
      redmine/app/views/admin/info.rhtml
  39. 12
      redmine/app/views/admin/mail_options.rhtml
  40. 18
      redmine/app/views/admin/projects.rhtml
  41. 49
      redmine/app/views/auth_sources/_form.rhtml
  42. 7
      redmine/app/views/auth_sources/edit.rhtml
  43. 32
      redmine/app/views/auth_sources/list.rhtml
  44. 6
      redmine/app/views/auth_sources/new.rhtml
  45. 55
      redmine/app/views/custom_fields/_form.rhtml
  46. 6
      redmine/app/views/custom_fields/edit.rhtml
  47. 29
      redmine/app/views/custom_fields/list.rhtml
  48. 7
      redmine/app/views/custom_fields/new.rhtml
  49. 10
      redmine/app/views/documents/_form.rhtml
  50. 2
      redmine/app/views/documents/show.rhtml
  51. 5
      redmine/app/views/issues/change_status.rhtml
  52. 27
      redmine/app/views/issues/edit.rhtml
  53. 11
      redmine/app/views/issues/show.rhtml
  54. 97
      redmine/app/views/layouts/base.rhtml
  55. 4
      redmine/app/views/mailer/_issue.rhtml
  56. 0
      redmine/app/views/mailer/issue_add_en.rhtml
  57. 3
      redmine/app/views/mailer/issue_add_fr.rhtml
  58. 0
      redmine/app/views/mailer/issue_change_status_en.rhtml
  59. 3
      redmine/app/views/mailer/issue_change_status_fr.rhtml
  60. 3
      redmine/app/views/mailer/lost_password_en.rhtml
  61. 3
      redmine/app/views/mailer/lost_password_fr.rhtml
  62. 3
      redmine/app/views/mailer/register_en.rhtml
  63. 3
      redmine/app/views/mailer/register_fr.rhtml
  64. 8
      redmine/app/views/news/_form.rhtml
  65. 4
      redmine/app/views/news/show.rhtml
  66. 17
      redmine/app/views/projects/_form.rhtml
  67. 1
      redmine/app/views/projects/add.rhtml
  68. 4
      redmine/app/views/projects/add_document.rhtml
  69. 33
      redmine/app/views/projects/add_issue.rhtml
  70. 2
      redmine/app/views/projects/changelog.rhtml
  71. 2
      redmine/app/views/projects/list.rhtml
  72. 2
      redmine/app/views/projects/list_documents.rhtml
  73. 8
      redmine/app/views/projects/list_issues.rhtml
  74. 2
      redmine/app/views/projects/list_news.rhtml
  75. 6
      redmine/app/views/projects/settings.rhtml
  76. 21
      redmine/app/views/projects/show.rhtml
  77. 5
      redmine/app/views/roles/_form.rhtml
  78. 2
      redmine/app/views/trackers/_form.rhtml
  79. 24
      redmine/app/views/users/_form.rhtml
  80. 6
      redmine/app/views/users/list.rhtml
  81. 4
      redmine/app/views/versions/_form.rhtml
  82. 9
      redmine/app/views/welcome/index.rhtml
  83. 57
      redmine/config/config_custom.rb
  84. 71
      redmine/config/environment.rb
  85. 1
      redmine/config/environments/test.rb
  86. 28
      redmine/doc/CHANGELOG
  87. 14
      redmine/doc/INSTALL
  88. 113
      redmine/lang/en.yml
  89. 2
      redmine/lang/en_US.rb
  90. 199
      redmine/lang/fr.yml
  91. 32
      redmine/lang/fr_FR.rb
  92. 24
      redmine/lib/tasks/extract_fixtures.rake
  93. BIN
      redmine/public/images/Copie de help.png
  94. BIN
      redmine/public/images/alert.png
  95. BIN
      redmine/public/images/login.png
  96. BIN
      redmine/public/images/logout.png
  97. 556
      redmine/public/javascripts/menu.js
  98. 27
      redmine/public/stylesheets/application.css
  99. 39
      redmine/public/stylesheets/menu.css
  100. 21
      redmine/public/stylesheets/rails.css
  101. Some files were not shown because too many files have changed in this diff Show More

@ -17,11 +17,14 @@
class AccountController < ApplicationController
layout 'base'
helper :custom_fields
include CustomFieldsHelper
# prevents login action to be filtered by check_if_login_required application scope filter
skip_before_filter :check_if_login_required, :only => :login
before_filter :require_login, :except => [:show, :login]
skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register]
before_filter :require_login, :except => [:show, :login, :lost_password, :register]
# Show user's account
def show
@user = User.find(params[:id])
end
@ -29,49 +32,123 @@ class AccountController < ApplicationController
# Login request and validation
def login
if request.get?
session[:user] = nil
# Logout user
self.logged_in_user = nil
else
logged_in_user = User.try_to_login(params[:login], params[:password])
if logged_in_user
session[:user] = logged_in_user
# Authenticate user
user = User.try_to_login(params[:login], params[:password])
if user
self.logged_in_user = user
redirect_back_or_default :controller => 'account', :action => 'my_page'
else
flash[:notice] = _('Invalid user/password')
flash[:notice] = l(:notice_account_invalid_creditentials)
end
end
end
# Log out current user and redirect to welcome page
def logout
session[:user] = nil
redirect_to(:controller => '')
end
def my_page
@user = session[:user]
@reported_issues = Issue.find(:all, :conditions => ["author_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')
@assigned_issues = Issue.find(:all, :conditions => ["assigned_to_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')
end
# Edit current user's account
def my_account
@user = User.find(session[:user].id)
if request.post? and @user.update_attributes(@params[:user])
flash[:notice] = 'Account was successfully updated.'
session[:user] = @user
# Log out current user and redirect to welcome page
def logout
self.logged_in_user = nil
redirect_to :controller => ''
end
# Show logged in user's page
def my_page
@user = self.logged_in_user
@reported_issues = Issue.find(:all, :conditions => ["author_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')
@assigned_issues = Issue.find(:all, :conditions => ["assigned_to_id=?", @user.id], :limit => 10, :include => [ :status, :project, :tracker ], :order => 'issues.updated_on DESC')
end
# Edit logged in user's account
def my_account
@user = self.logged_in_user
if request.post? and @user.update_attributes(@params[:user])
set_localization
end
end
flash[:notice] = l(:notice_account_updated)
self.logged_in_user.reload
end
end
# Change current user's password
# Change logged in user's password
def change_password
@user = User.find(session[:user].id)
@user = self.logged_in_user
if @user.check_password?(@params[:password])
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
flash[:notice] = 'Password was successfully updated.' if @user.save
flash[:notice] = l(:notice_account_password_updated) if @user.save
else
flash[:notice] = 'Wrong password'
flash[:notice] = l(:notice_account_wrong_password)
end
render :action => 'my_account'
end
end
# Enable user to choose a new password
def lost_password
if params[:token]
@token = Token.find_by_action_and_value("recovery", params[:token])
redirect_to :controller => '' and return unless @token and !@token.expired?
@user = @token.user
if request.post?
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
if @user.save
@token.destroy
flash[:notice] = l(:notice_account_password_updated)
redirect_to :action => 'login'
return
end
end
render :template => "account/password_recovery"
return
else
if request.post?
user = User.find_by_mail(params[:mail])
flash[:notice] = l(:notice_account_unknown_email) and return unless user
token = Token.new(:user => user, :action => "recovery")
if token.save
Mailer.set_language_if_valid(Localization.lang)
Mailer.deliver_lost_password(token)
flash[:notice] = l(:notice_account_lost_email_sent)
redirect_to :action => 'login'
return
end
end
end
end
# User self-registration
def register
redirect_to :controller => '' and return if $RDM_SELF_REGISTRATION == false
if params[:token]
token = Token.find_by_action_and_value("register", params[:token])
redirect_to :controller => '' and return unless token and !token.expired?
user = token.user
redirect_to :controller => '' and return unless user.status == User::STATUS_REGISTERED
user.status = User::STATUS_ACTIVE
if user.save
token.destroy
flash[:notice] = l(:notice_account_activated)
redirect_to :action => 'login'
return
end
else
if request.get?
@user = User.new(:language => $RDM_DEFAULT_LANG)
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
else
@user = User.new(params[:user])
@user.admin = false
@user.login = params[:user][:login]
@user.status = User::STATUS_REGISTERED
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
@user.custom_values = @custom_values
token = Token.new(:user => @user, :action => "register")
if @user.save and token.save
Mailer.set_language_if_valid(Localization.lang)
Mailer.deliver_register(token)
flash[:notice] = l(:notice_account_register_done)
redirect_to :controller => ''
end
end
end
end
end

@ -18,43 +18,59 @@
class ApplicationController < ActionController::Base
before_filter :check_if_login_required, :set_localization
def logged_in_user=(user)
@logged_in_user = user
session[:user_id] = (user ? user.id : nil)
end
def logged_in_user
if session[:user_id]
@logged_in_user ||= User.find(session[:user_id], :include => :memberships)
else
nil
end
end
# check if login is globally required to access the application
def check_if_login_required
require_login if RDM_LOGIN_REQUIRED
require_login if $RDM_LOGIN_REQUIRED
end
def set_localization
Localization.lang = begin
if session[:user]
session[:user].language
if self.logged_in_user and Localization.langs.keys.include? self.logged_in_user.language
self.logged_in_user.language
elsif request.env['HTTP_ACCEPT_LANGUAGE']
accept_lang = HTTPUtils.parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
if Localization.langs.collect{ |l| l[1] }.include? accept_lang
if Localization.langs.keys.include? accept_lang
accept_lang
end
end
rescue
nil
end || RDM_DEFAULT_LANG
end || $RDM_DEFAULT_LANG
set_language_if_valid(Localization.lang)
end
def require_login
unless session[:user]
unless self.logged_in_user
store_location
redirect_to(:controller => "account", :action => "login")
return false
end
true
end
def require_admin
if session[:user].nil?
store_location
redirect_to(:controller => "account", :action => "login")
else
unless session[:user].admin?
flash[:notice] = "Acces not allowed"
redirect_to(:controller => "projects", :action => "list")
end
return unless require_login
unless self.logged_in_user.admin?
flash[:notice] = "Acces denied"
redirect_to:controller => ''
return false
end
true
end
# authorizes the user for the requested action.
@ -62,19 +78,18 @@ class ApplicationController < ActionController::Base
# check if action is allowed on public projects
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ @params[:controller], @params[:action] ]
return true
end
# if user not logged in, redirect to login form
unless session[:user]
store_location
redirect_to(:controller => "account", :action => "login")
return false
end
# if logged in, check if authorized
if session[:user].admin? or Permission.allowed_to_role( "%s/%s" % [ @params[:controller], @params[:action] ], session[:user].role_for_project(@project.id) )
end
# if action is not public, force login
return unless require_login
# admin is always authorized
return true if self.logged_in_user.admin?
# if not admin, check membership permission
@user_membership ||= Member.find(:first, :conditions => ["user_id=? and project_id=?", self.logged_in_user.id, @project.id])
if @user_membership and Permission.allowed_to_role( "%s/%s" % [ @params[:controller], @params[:action] ], @user_membership.role_id )
return true
end
flash[:notice] = "Acces denied"
redirect_to(:controller => "")
redirect_to :controller => ''
false
end

@ -0,0 +1,82 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class AuthSourcesController < ApplicationController
layout 'base'
before_filter :require_admin
def index
list
render :action => 'list'
end
# GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
verify :method => :post, :only => [ :destroy, :create, :update ],
:redirect_to => { :action => :list }
def list
@auth_source_pages, @auth_sources = paginate :auth_sources, :per_page => 10
end
def new
@auth_source = AuthSourceLdap.new
end
def create
@auth_source = AuthSourceLdap.new(params[:auth_source])
if @auth_source.save
flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'list'
else
render :action => 'new'
end
end
def edit
@auth_source = AuthSource.find(params[:id])
end
def update
@auth_source = AuthSource.find(params[:id])
if @auth_source.update_attributes(params[:auth_source])
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list'
else
render :action => 'edit'
end
end
def test_connection
@auth_method = AuthSource.find(params[:id])
begin
@auth_method.test_connection
rescue => text
flash[:notice] = text
end
flash[:notice] ||= l(:notice_successful_connection)
redirect_to :action => 'list'
end
def destroy
@auth_source = AuthSource.find(params[:id])
unless @auth_source.users.find(:first)
@auth_source.destroy
flash[:notice] = l(:notice_successful_delete)
end
redirect_to :action => 'list'
end
end

@ -16,37 +16,48 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomFieldsController < ApplicationController
layout 'base'
before_filter :require_admin
layout 'base'
before_filter :require_admin
def index
list
render :action => 'list'
end
def list
@custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 10
@custom_field_pages, @custom_fields = paginate :custom_fields, :per_page => 15
end
def new
if request.get?
@custom_field = CustomField.new
else
@custom_field = CustomField.new(params[:custom_field])
if @custom_field.save
flash[:notice] = 'CustomField was successfully created.'
redirect_to :action => 'list'
case params[:type]
when "IssueCustomField"
@custom_field = IssueCustomField.new(params[:custom_field])
@custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids]
when "UserCustomField"
@custom_field = UserCustomField.new(params[:custom_field])
when "ProjectCustomField"
@custom_field = ProjectCustomField.new(params[:custom_field])
else
redirect_to :action => 'list'
return
end
if request.post? and @custom_field.save
redirect_to :action => 'list'
end
@trackers = Tracker.find(:all)
end
def edit
@custom_field = CustomField.find(params[:id])
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
end
end
def edit
@custom_field = CustomField.find(params[:id])
if request.post? and @custom_field.update_attributes(params[:custom_field])
flash[:notice] = 'CustomField was successfully updated.'
redirect_to :action => 'list'
end
end
flash[:notice] = 'Custom field was successfully updated.'
redirect_to :action => 'list'
end
@trackers = Tracker.find(:all)
end
def destroy
CustomField.find(params[:id]).destroy
@ -54,5 +65,5 @@ class CustomFieldsController < ApplicationController
rescue
flash[:notice] = "Unable to delete custom field"
redirect_to :action => 'list'
end
end
end

@ -45,7 +45,7 @@ class DocumentsController < ApplicationController
# Save the attachment
if params[:attachment][:file].size > 0
@attachment = @document.attachments.build(params[:attachment])
@attachment.author_id = session[:user].id unless session[:user].nil?
@attachment.author_id = self.logged_in_user.id if self.logged_in_user
@attachment.save
end
render :action => 'show'

@ -23,21 +23,21 @@ class IssuesController < ApplicationController
include CustomFieldsHelper
def show
@status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", session[:user].role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if session[:user]
@status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user
@custom_values = @issue.custom_values.find(:all, :include => :custom_field)
end
def edit
@trackers = Tracker.find(:all)
def edit
@priorities = Enumeration::get_values('IPRI')
if request.get?
@custom_values = @project.custom_fields_for_issues.collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| @issue.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x, :customized => @issue) }
else
# Retrieve custom fields and values
@custom_values = @project.custom_fields_for_issues.collect { |x| CustomValue.new(:custom_field => x, :value => params["custom_fields"][x.id.to_s]) }
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
@issue.custom_values = @custom_values
if @issue.update_attributes(params[:issue])
@issue.attributes = params[:issue]
if @issue.save
flash[:notice] = 'Issue was successfully updated.'
redirect_to :action => 'show', :id => @issue
end
@ -46,12 +46,11 @@ class IssuesController < ApplicationController
def change_status
@history = @issue.histories.build(params[:history])
@status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", session[:user].role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if session[:user]
@status_options = @issue.status.workflows.find(:all, :conditions => ["role_id=? and tracker_id=?", self.logged_in_user.role_for_project(@project.id), @issue.tracker.id]).collect{ |w| w.new_status } if self.logged_in_user
if params[:confirm]
unless session[:user].nil?
@history.author = session[:user]
end
@history.author_id = self.logged_in_user.id if self.logged_in_user
if @history.save
@issue.status = @history.status
@issue.fixed_version_id = (params[:issue][:fixed_version_id])
@ -76,7 +75,7 @@ class IssuesController < ApplicationController
# Save the attachment
if params[:attachment][:file].size > 0
@attachment = @issue.attachments.build(params[:attachment])
@attachment.author_id = session[:user].id unless session[:user].nil?
@attachment.author_id = self.logged_in_user.id if self.logged_in_user
@attachment.save
end
redirect_to :action => 'show', :id => @issue
@ -86,17 +85,16 @@ class IssuesController < ApplicationController
@issue.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'show', :id => @issue
end
# Send the file in stream mode
def download
@attachment = @issue.attachments.find(params[:attachment_id])
send_file @attachment.diskfile, :filename => @attachment.filename
end
# Send the file in stream mode
def download
@attachment = @issue.attachments.find(params[:attachment_id])
send_file @attachment.diskfile, :filename => @attachment.filename
end
private
def find_project
def find_project
@issue = Issue.find(params[:id])
@project = @issue.project
end
@project = @issue.project
end
end

@ -48,11 +48,15 @@ class ProjectsController < ApplicationController
# Add a new project
def add
@custom_fields = CustomField::find_all
@root_projects = Project::find(:all, :conditions => "parent_id is null")
@custom_fields = IssueCustomField.find(:all)
@root_projects = Project.find(:all, :conditions => "parent_id is null")
@project = Project.new(params[:project])
if request.post?
@project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
if request.get?
@custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
else
@project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
@custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
@project.custom_values = @custom_values
if @project.save
flash[:notice] = 'Project was successfully created.'
redirect_to :controller => 'admin', :action => 'projects'
@ -60,26 +64,33 @@ class ProjectsController < ApplicationController
end
end
# Show @project
# Show @project
def show
@custom_values = @project.custom_values.find(:all, :include => :custom_field)
@members = @project.members.find(:all, :include => [:user, :role])
@subprojects = @project.children if @project.children_count > 0
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC")
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "news.created_on DESC")
@trackers = Tracker.find(:all)
end
def settings
@root_projects = Project::find(:all, :conditions => ["parent_id is null and id <> ?", @project.id])
@custom_fields = CustomField::find_all
@custom_fields = IssueCustomField::find_all
@issue_category ||= IssueCategory.new
@member ||= @project.members.new
@roles = Role.find_all
@users = User.find_all - @project.members.find(:all, :include => :user).collect{|m| m.user }
@custom_values = ProjectCustomField.find(:all).collect { |x| @project.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
end
# Edit @project
def edit
if request.post?
@project.custom_fields = CustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
@project.custom_fields = IssueCustomField.find(@params[:custom_field_ids]) if @params[:custom_field_ids]
if params[:custom_fields]
@custom_values = ProjectCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => params["custom_fields"][x.id.to_s]) }
@project.custom_values = @custom_values
end
if @project.update_attributes(params[:project])
flash[:notice] = 'Project was successfully updated.'
redirect_to :action => 'settings', :id => @project
@ -89,102 +100,101 @@ class ProjectsController < ApplicationController
end
end
end
# Delete @project
def destroy
# Delete @project
def destroy
if request.post? and params[:confirm]
@project.destroy
redirect_to :controller => 'admin', :action => 'projects'
end
end
end
# Add a new issue category to @project
def add_issue_category
if request.post?
@issue_category = @project.issue_categories.build(params[:issue_category])
if @issue_category.save
redirect_to :action => 'settings', :id => @project
else
# Add a new issue category to @project
def add_issue_category
if request.post?
@issue_category = @project.issue_categories.build(params[:issue_category])
if @issue_category.save
redirect_to :action => 'settings', :id => @project
else
settings
render :action => 'settings'
end
end
end
end
end
end
# Add a new version to @project
def add_version
@version = @project.versions.build(params[:version])
if request.post? and @version.save
# Add a new version to @project
def add_version
@version = @project.versions.build(params[:version])
if request.post? and @version.save
redirect_to :action => 'settings', :id => @project
end
end
end
end
# Add a new member to @project
def add_member
# Add a new member to @project
def add_member
@member = @project.members.build(params[:member])
if request.post?
if @member.save
if request.post?
if @member.save
flash[:notice] = 'Member was successfully added.'
redirect_to :action => 'settings', :id => @project
else
redirect_to :action => 'settings', :id => @project
else
settings
render :action => 'settings'
end
end
end
end
end
# Show members list of @project
def list_members
@members = @project.members
end
# Show members list of @project
def list_members
@members = @project.members
end
# Add a new document to @project
def add_document
@categories = Enumeration::get_values('DCAT')
@document = @project.documents.build(params[:document])
if request.post?
# Add a new document to @project
def add_document
@categories = Enumeration::get_values('DCAT')
@document = @project.documents.build(params[:document])
if request.post?
# Save the attachment
if params[:attachment][:file].size > 0
@attachment = @document.attachments.build(params[:attachment])
@attachment.author_id = session[:user].id unless session[:user].nil?
end
if @document.save
redirect_to :action => 'list_documents', :id => @project
end
end
end
# Show documents list of @project
def list_documents
@documents = @project.documents
end
if params[:attachment][:file].size > 0
@attachment = @document.attachments.build(params[:attachment])
@attachment.author_id = self.logged_in_user.id if self.logged_in_user
end
if @document.save
redirect_to :action => 'list_documents', :id => @project
end
end
end
# Show documents list of @project
def list_documents
@documents = @project.documents
end
# Add a new issue to @project
def add_issue
@trackers = Tracker.find(:all)
@priorities = Enumeration::get_values('IPRI')
if request.get?
@issue = @project.issues.build
@custom_values = @project.custom_fields_for_issues.collect { |x| CustomValue.new(:custom_field => x) }
else
# Create the issue and set the author
@issue = @project.issues.build(params[:issue])
@issue.author = session[:user] unless session[:user].nil?
# Create the document if a file was sent
if params[:attachment][:file].size > 0
@attachment = @issue.attachments.build(params[:attachment])
@attachment.author_id = session[:user].id unless session[:user].nil?
end
@custom_values = @project.custom_fields_for_issues.collect { |x| CustomValue.new(:custom_field => x, :value => params["custom_fields"][x.id.to_s]) }
@issue.custom_values = @custom_values
if @issue.save
# Add a new issue to @project
def add_issue
@tracker = Tracker.find(params[:tracker_id])
@priorities = Enumeration::get_values('IPRI')
@issue = Issue.new(:project => @project, :tracker => @tracker)
if request.get?
@custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue) }
else
@issue.attributes = params[:issue]
@issue.author_id = self.logged_in_user.id if self.logged_in_user
# Create the document if a file was sent
if params[:attachment][:file].size > 0
@attachment = @issue.attachments.build(params[:attachment])
@attachment.author_id = self.logged_in_user.id if self.logged_in_user
end
@custom_values = @project.custom_fields_for_issues(@tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
@issue.custom_values = @custom_values
if @issue.save
flash[:notice] = "Issue was successfully added."
Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
redirect_to :action => 'list_issues', :id => @project
end
end
end
Mailer.deliver_issue_add(@issue) if Permission.find_by_controller_and_action(@params[:controller], @params[:action]).mail_enabled?
redirect_to :action => 'list_issues', :id => @project
end
end
end
# Show filtered/sorted issues list of @project
def list_issues
sort_init 'issues.id', 'desc'
@ -195,11 +205,11 @@ class ProjectsController < ApplicationController
@issue_count = Issue.count(:include => [:status, :project], :conditions => search_filter_clause)
@issue_pages = Paginator.new self, @issue_count, 15, @params['page']
@issues = Issue.find :all, :order => sort_clause,
@issues = Issue.find :all, :order => sort_clause,
:include => [ :author, :status, :tracker, :project ],
:conditions => search_filter_clause,
:limit => @issue_pages.items_per_page,
:offset => @issue_pages.current.offset
:offset => @issue_pages.current.offset
end
# Export filtered/sorted issues list to CSV
@ -225,29 +235,30 @@ class ProjectsController < ApplicationController
:type => 'text/csv; charset=utf-8; header=present',
:filename => 'export.csv')
end
# Add a news to @project
def add_news
@news = @project.news.build(params[:news])
if request.post?
@news.author = session[:user] unless session[:user].nil?
if @news.save
redirect_to :action => 'list_news', :id => @project
end
end
end
# Show news list of @project
# Add a news to @project
def add_news
@news = News.new(:project => @project)
if request.post?
@news.attributes = params[:news]
@news.author_id = self.logged_in_user.id if self.logged_in_user
if @news.save
redirect_to :action => 'list_news', :id => @project
end
end
end
# Show news list of @project
def list_news
@news_pages, @news = paginate :news, :per_page => 10, :conditions => ["project_id=?", @project.id], :include => :author, :order => "news.created_on DESC"
end
def add_file
if request.post?
# Save the attachment
if params[:attachment][:file].size > 0
@attachment = @project.versions.find(params[:version_id]).attachments.build(params[:attachment])
@attachment.author_id = session[:user].id unless session[:user].nil?
@attachment.author_id = self.logged_in_user.id if self.logged_in_user
if @attachment.save
redirect_to :controller => 'projects', :action => 'list_files', :id => @project
end
@ -269,14 +280,13 @@ class ProjectsController < ApplicationController
end
private
# Find project of id params[:id]
# if not found, redirect to project list
# used as a before_filter
def find_project
@project = Project.find(params[:id])
rescue
flash[:notice] = 'Project not found.'
redirect_to :action => 'list'
end
# Find project of id params[:id]
# if not found, redirect to project list
# used as a before_filter
def find_project
@project = Project.find(params[:id])
rescue
flash[:notice] = 'Project not found.'
redirect_to :action => 'list'
end
end

@ -21,6 +21,8 @@ class UsersController < ApplicationController
helper :sort
include SortHelper
helper :custom_fields
include CustomFieldsHelper
def index
list
@ -41,12 +43,15 @@ class UsersController < ApplicationController
def add
if request.get?
@user = User.new
@user = User.new(:language => $RDM_DEFAULT_LANG)
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
else
@user = User.new(params[:user])
@user.admin = params[:user][:admin] || false
@user.login = params[:user][:login]
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation]
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
@user.custom_values = @custom_values
if @user.save
flash[:notice] = 'User was successfully created.'
redirect_to :action => 'list'
@ -56,10 +61,16 @@ class UsersController < ApplicationController
def edit
@user = User.find(params[:id])
if request.post?
if request.get?
@custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
else
@user.admin = params[:user][:admin] if params[:user][:admin]
@user.login = params[:user][:login] if params[:user][:login]
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty?
if params[:custom_fields]
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) }
@user.custom_values = @custom_values
end
if @user.update_attributes(params[:user])
flash[:notice] = 'User was successfully updated.'
redirect_to :action => 'list'

@ -16,11 +16,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class WelcomeController < ApplicationController
layout 'base'
def index
layout 'base'
def index
@news = News.latest
@projects = Project.latest
end
end
end

@ -17,35 +17,38 @@
module ApplicationHelper
def loggedin?
session[:user]
end
# return current logged in user or nil
def loggedin?
@logged_in_user
end
# return true if user is loggend in and is admin, otherwise false
def admin_loggedin?
@logged_in_user and @logged_in_user.admin?
end
def admin_loggedin?
session[:user] && session[:user].admin
end
def authorize_for(controller, action)
def authorize_for(controller, action)
# check if action is allowed on public projects
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ]
return true
end
end
# check if user is authorized
if session[:user] and (session[:user].admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], session[:user].role_for_project(@project.id) ) )
return true
end
return false
end
def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
end
# Display a link to user's account page
def link_to_user(user)
link_to user.display_name, :controller => 'account', :action => 'show', :id => user
end
if @logged_in_user and (@logged_in_user.admin? or Permission.allowed_to_role( "%s/%s" % [ controller, action ], @logged_in_user.role_for_project(@project.id) ) )
return true
end
return false
end
# Display a link if user is authorized
def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference)
link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
end
# Display a link to user's account page
def link_to_user(user)
link_to user.display_name, :controller => 'account', :action => 'show', :id => user
end
def format_date(date)
_('(date)', date) if date
end
@ -61,5 +64,30 @@ module ApplicationHelper
html << ' ' + link_to((_('Next') + ' &#187;'), { :page => paginator.current.next }) if paginator.current.next
html
end
def error_messages_for(object_name, options = {})
options = options.symbolize_keys
object = instance_variable_get("@#{object_name}")
if object && !object.errors.empty?
# build full_messages here with controller current language
full_messages = []
object.errors.each do |attr, msg|
next if msg.nil?
if attr == "base"
full_messages << l(msg)
else
full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg)
end
end
content_tag("div",
content_tag(
options[:header_tag] || "h2", lwr(:gui_validation_error, object.errors.count) + " :"
) +
content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
"id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
)
else
""
end
end
end

@ -0,0 +1,19 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module AuthSourcesHelper
end

@ -16,21 +16,49 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module CustomFieldsHelper
def custom_field_tag(custom_value)
custom_field = custom_value.custom_field
field_name = "custom_fields[#{custom_field.id}]"
case custom_field.typ
when 0 .. 2
text_field_tag field_name, custom_value.value
when 3
check_box field_name
when 4
select_tag field_name,
options_for_select(custom_field.possible_values.split('|'),
custom_value.value)
end
end
def custom_field_tag(custom_value)
custom_field = custom_value.custom_field
field_name = "custom_fields[#{custom_field.id}]"
case custom_field.field_format
when "string", "int", "date"
text_field_tag field_name, custom_value.value
when "text"
text_area_tag field_name, custom_value.value, :cols => 60, :rows => 3
when "bool"
check_box_tag(field_name, "1", custom_value.value == "1") +
hidden_field_tag(field_name, "0")
when "list"
select_tag field_name,
"<option></option>" + options_for_select(custom_field.possible_values.split('|'),
custom_value.value)
end
end
def custom_field_label_tag(custom_value)
content_tag "label", custom_value.custom_field.name +
(custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : "")
end
def custom_field_tag_with_label(custom_value)
case custom_value.custom_field.field_format
when "bool"
custom_field_tag(custom_value) + " " + custom_field_label_tag(custom_value)
else
custom_field_label_tag(custom_value) + "<br />" + custom_field_tag(custom_value)
end
end
def show_value(custom_value)
case custom_value.custom_field.field_format
when "bool"
l_YesNo(custom_value.value == "1")
else
custom_value.value
end
end
def custom_field_formats_for_select
CustomField::FIELD_FORMATS.keys.collect { |k| [ l(CustomField::FIELD_FORMATS[k]), k ] }
end
end

@ -55,7 +55,7 @@ class Attachment < ActiveRecord::Base
# Returns file's location on disk
def diskfile
"#{RDM_STORAGE_PATH}/#{self.disk_filename}"
"#{$RDM_STORAGE_PATH}/#{self.disk_filename}"
end
def increment_download

@ -0,0 +1,47 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class AuthSource < ActiveRecord::Base
has_many :users
validates_presence_of :name
validates_uniqueness_of :name
def authenticate(login, password)
end
def test_connection
end
def auth_method_name
"Abstract"
end
# Try to authenticate a user not yet registered against available sources
def self.authenticate(login, password)
AuthSource.find(:all, :conditions => ["onthefly_register=?", true]).each do |source|
begin
logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug?
attrs = source.authenticate(login, password)
rescue
attrs = nil
end
return attrs if attrs
end
return nil
end
end

@ -0,0 +1,79 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'net/ldap'
require 'iconv'
class AuthSourceLdap < AuthSource
validates_presence_of :host, :port, :attr_login
def after_initialize
self.port = 389 if self.port == 0
end
def authenticate(login, password)
attrs = []
# get user's DN
ldap_con = initialize_ldap_con(self.account, self.account_password)
login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
object_filter = Net::LDAP::Filter.eq( "objectClass", "organizationalPerson" )
dn = String.new
ldap_con.search( :base => self.base_dn,
:filter => object_filter & login_filter,
:attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry|
dn = entry.dn
attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
:lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
:mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
:auth_source_id => self.id ]
end
return nil if dn.empty?
logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
# authenticate user
ldap_con = initialize_ldap_con(dn, password)
return nil unless ldap_con.bind
# return user's attributes
logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
attrs
rescue Net::LDAP::LdapError => text
raise "LdapError: " + text
end
# test the connection to the LDAP
def test_connection
ldap_con = initialize_ldap_con(self.account, self.account_password)
ldap_con.open { }
rescue Net::LDAP::LdapError => text
raise "LdapError: " + text
end
def auth_method_name
"LDAP"
end
private
def initialize_ldap_con(ldap_user, ldap_password)
Net::LDAP.new( {:host => self.host,
:port => self.port,
:auth => { :method => :simple, :username => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_user), :password => Iconv.new('iso-8859-15', 'utf-8').iconv(ldap_password) }}
)
end
def self.get_attr(entry, attr_name)
entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
end
end

@ -16,23 +16,27 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomField < ActiveRecord::Base
has_many :custom_values, :dependent => true
has_and_belongs_to_many :projects
has_many :custom_values, :dependent => true
has_many :issues, :through => :issue_custom_values
FIELD_FORMATS = { "list" => :label_list,
"date" => :label_date,
"bool" => :label_boolean,
"int" => :label_integer,
"string" => :label_string,
"text" => :label_text
}.freeze
validates_presence_of :name, :typ
validates_uniqueness_of :name
validates_presence_of :name, :field_format
validates_uniqueness_of :name
validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys
validates_presence_of :possible_values, :if => Proc.new { |field| field.field_format == "list" }
TYPES = [
[ "Integer", 0 ],
[ "String", 1 ],
[ "Date", 2 ],
[ "Boolean", 3 ],
[ "List", 4 ]
].freeze
def self.for_all
find(:all, :conditions => ["is_for_all=?", true])
end
end
# to move in project_custom_field
def self.for_all
find(:all, :conditions => ["is_for_all=?", true])
end
def type_name
nil
end
end

@ -16,26 +16,28 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomValue < ActiveRecord::Base
belongs_to :issue
belongs_to :custom_field
belongs_to :custom_field
belongs_to :customized, :polymorphic => true
protected
def validate
errors.add(custom_field.name, "can't be blank") if custom_field.is_required? and value.empty?
errors.add(custom_field.name, "is not valid") unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp)
case custom_field.typ
when 0
errors.add(custom_field.name, "must be an integer") unless value =~ /^[0-9]*$/
when 1
errors.add(custom_field.name, "is too short") if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0
errors.add(custom_field.name, "is too long") if custom_field.max_length > 0 and value.length > custom_field.max_length
when 2
errors.add(custom_field.name, "must be a valid date") unless value =~ /^(\d+)\/(\d+)\/(\d+)$/ or value.empty?
when 3
when 4
errors.add(custom_field.name, "is not a valid value") unless custom_field.possible_values.split('|').include? value or value.empty?
end
# errors are added to customized object unless it's nil
object = customized || self
object.errors.add(custom_field.name, :activerecord_error_blank) if custom_field.is_required? and value.empty?
object.errors.add(custom_field.name, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp)
object.errors.add(custom_field.name, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0
object.errors.add(custom_field.name, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length
case custom_field.field_format
when "int"
object.errors.add(custom_field.name, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/
when "date"
object.errors.add(custom_field.name, :activerecord_error_invalid) unless value =~ /^(\d+)\/(\d+)\/(\d+)$/ or value.empty?
when "list"
object.errors.add(custom_field.name, :activerecord_error_inclusion) unless custom_field.possible_values.split('|').include? value or value.empty?
end
end
end
end

@ -20,5 +20,5 @@ class Document < ActiveRecord::Base
belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
has_many :attachments, :as => :container, :dependent => true
validates_presence_of :title
validates_presence_of :project, :title, :category
end

@ -29,15 +29,19 @@ class Issue < ActiveRecord::Base
has_many :histories, :class_name => 'IssueHistory', :dependent => true, :order => "issue_histories.created_on DESC", :include => :status
has_many :attachments, :as => :container, :dependent => true
has_many :custom_values, :dependent => true
has_many :custom_values, :dependent => true, :as => :customized
has_many :custom_fields, :through => :custom_values
validates_presence_of :subject, :descr, :priority, :tracker, :author
validates_presence_of :subject, :description, :priority, :tracker, :author
validates_associated :custom_values, :on => :update
# set default status for new issues
def before_validation
self.status = IssueStatus.default if new_record?
end
def before_create
self.status = IssueStatus.default
build_history
build_history
end
def long_id

@ -0,0 +1,27 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueCustomField < CustomField
has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id"
has_and_belongs_to_many :trackers, :join_table => "custom_fields_trackers", :foreign_key => "custom_field_id"
has_many :issues, :through => :issue_custom_values
def type_name
:label_issue_plural
end
end

@ -17,20 +17,34 @@
class Mailer < ActionMailer::Base
def issue_change_status(issue)
# Sends to all project members
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
@from = 'redmine@somenet.foo'
@subject = "Issue ##{issue.id} has been updated"
@body['issue'] = issue
end
def issue_add(issue)
# Sends to all project members
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
@from = 'redmine@somenet.foo'
@subject = "Issue ##{issue.id} has been reported"
@body['issue'] = issue
end
def issue_change_status(issue)
# Sends to all project members
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
@from = 'redmine@somenet.foo'
@subject = "Issue ##{issue.id} has been updated"
@body['issue'] = issue
end
def issue_add(issue)
# Sends to all project members
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }
@from = 'redmine@somenet.foo'
@subject = "Issue ##{issue.id} has been reported"
@body['issue'] = issue
end
def lost_password(token)
@recipients = token.user.mail
@from = 'redmine@somenet.foo'
@subject = "redMine password"
@body['token'] = token
end
def register(token)
@recipients = token.user.mail
@from = 'redmine@somenet.foo'
@subject = "redMine account activation"
@body['token'] = token
end
end

@ -19,7 +19,7 @@ class News < ActiveRecord::Base
belongs_to :project
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :title, :shortdescr, :descr
validates_presence_of :title, :description
# returns last created news
def self.latest

@ -18,7 +18,7 @@
class Permission < ActiveRecord::Base
has_and_belongs_to_many :roles
validates_presence_of :controller, :action, :descr
validates_presence_of :controller, :action, :description
GROUPS = {
100 => "Project",

@ -16,30 +16,34 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Project < ActiveRecord::Base
has_many :versions, :dependent => true, :order => "versions.effective_date DESC"
has_many :members, :dependent => true
has_many :users, :through => :members
has_many :issues, :dependent => true, :order => "issues.created_on DESC", :include => :status
has_many :documents, :dependent => true
has_many :news, :dependent => true, :include => :author
has_many :issue_categories, :dependent => true
has_and_belongs_to_many :custom_fields
acts_as_tree :order => "name", :counter_cache => true
validates_presence_of :name, :descr
validates_uniqueness_of :name
# returns 5 last created projects
def self.latest
find(:all, :limit => 5, :order => "created_on DESC")
end
# Returns an array of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects)
def custom_fields_for_issues
(CustomField.for_all + custom_fields).uniq
end
has_many :versions, :dependent => true, :order => "versions.effective_date DESC, versions.name DESC"
has_many :members, :dependent => true
has_many :users, :through => :members
has_many :custom_values, :dependent => true, :as => :customized
has_many :issues, :dependent => true, :order => "issues.created_on DESC", :include => :status
has_many :documents, :dependent => true
has_many :news, :dependent => true, :include => :author
has_many :issue_categories, :dependent => true, :order => "issue_categories.name"
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id'
acts_as_tree :order => "name", :counter_cache => true
validates_presence_of :name, :description
validates_uniqueness_of :name
validates_associated :custom_values, :on => :update
# returns 5 last created projects
def self.latest
find(:all, :limit => 5, :order => "created_on DESC")
end
# Returns an array of all custom fields enabled for project issues
# (explictly associated custom fields and custom fields enabled for all projects)
def custom_fields_for_issues(tracker)
tracker.custom_fields.find(:all, :include => :projects,
:conditions => ["is_for_all=? or project_id=?", true, self.id])
#(CustomField.for_all + custom_fields).uniq
end
protected
def validate
errors.add(parent_id, " must be a root project") if parent and parent.parent

@ -0,0 +1,22 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ProjectCustomField < CustomField
def type_name
:label_project_plural
end
end

@ -0,0 +1,44 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Token < ActiveRecord::Base
belongs_to :user
@@validity_time = 1.day
def before_create
self.value = Token.generate_token_value
end
# Return true if token has expired
def expired?
return Time.now > self.created_on + @@validity_time
end
# Delete all expired tokens
def self.destroy_expired
Token.delete_all ["created_on < ?", Time.now - @@validity_time]
end
private
def self.generate_token_value
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
token_value = ''
40.times { |i| token_value << chars[rand(chars.size-1)] }
token_value
end
end

@ -19,7 +19,8 @@ class Tracker < ActiveRecord::Base
before_destroy :check_integrity
has_many :issues
has_many :workflows, :dependent => true
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id'
validates_presence_of :name
validates_uniqueness_of :name

@ -19,7 +19,9 @@ require "digest/sha1"
class User < ActiveRecord::Base
has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => true
has_many :custom_values, :dependent => true, :as => :customized
belongs_to :auth_source
attr_accessor :password, :password_confirmation
attr_accessor :last_before_login_on
# Prevents unauthorized assignments
@ -33,6 +35,12 @@ class User < ActiveRecord::Base
# Password length between 4 and 12
validates_length_of :password, :in => 4..12, :allow_nil => true
validates_confirmation_of :password, :allow_nil => true
validates_associated :custom_values, :on => :update
# Account statuses
STATUS_ACTIVE = 1
STATUS_REGISTERED = 2
STATUS_LOCKED = 3
def before_save
# update hashed_password if password was set
@ -41,23 +49,52 @@ class User < ActiveRecord::Base
# Returns the user that matches provided login and password, or nil
def self.try_to_login(login, password)
user = find(:first, :conditions => ["login=? and hashed_password=? and locked=?", login, User.hash_password(password), false])
user = find(:first, :conditions => ["login=?", login])
if user
user.last_before_login_on = user.last_login_on
user.update_attribute(:last_login_on, Time.now)
end
# user is already in local database
return nil if !user.active?
if user.auth_source
# user has an external authentication method
return nil unless user.auth_source.authenticate(login, password)
else
# local authentication
return nil unless User.hash_password(password) == user.hashed_password
end
else
# user is not yet registered, try to authenticate with available sources
attrs = AuthSource.authenticate(login, password)
if attrs
onthefly = new(*attrs)
onthefly.login = login
onthefly.language = $RDM_DEFAULT_LANG
if onthefly.save
user = find(:first, :conditions => ["login=?", login])
end
end
end
user.update_attribute(:last_login_on, Time.now) if user
user
rescue => text
raise text
end
# Return user's full name for display
def display_name
firstname + " " + lastname
end
def active?
self.status == STATUS_ACTIVE
end
def locked?
self.status == STATUS_LOCKED
end
def check_password?(clear_password)
User.hash_password(clear_password) == self.hashed_password
end
def role_for_project(project_id)
@role_for_projects ||=

@ -0,0 +1,23 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class UserCustomField < CustomField
def type_name
:label_user_plural
end
end

@ -1,13 +1,25 @@
<div class="box">
<h2><%=_('Please login') %></h2>
<center>
<div class="box login">
<h2><%= image_tag 'login' %>&nbsp;&nbsp;<%=l(:label_please_login)%></h2>
<%= start_form_tag :action=> "login" %>
<p><label for="login"><%=_ 'Login' %>:</label><br/>
<%= text_field_tag 'login', nil, :size => 25 %></p>
<p><label for="user_password"><%=_ 'Password' %>:</label><br/>
<%= password_field_tag 'password', nil, :size => 25 %></p>
<%= start_form_tag :action=> "login" %>
<table cellpadding="4">
<tr>
<td><label for="login"><%=l(:field_login)%>:</label></td>
<td><%= text_field_tag 'login', nil, :size => 25 %></td>
</tr>
<tr>
<td><label for="password"><%=l(:field_password)%>:</label></td>
<td><%= password_field_tag 'password', nil, :size => 25 %></td>
</tr>
</table>
&nbsp;
<p><input type="submit" name="login" value="<%=_ 'Log in' %> &#187;" class="primary" /></p>
<%= end_form_tag %>
</div>
<p><center><input type="submit" name="login" value="<%=l(:button_login)%> &#187;" class="primary" /></center></p>
<%= end_form_tag %>
<br />
<% unless $RDM_SELF_REGISTRATION == false %><%= link_to l(:label_register), :action => 'register' %> |<% end %>
<%= link_to l(:label_password_lost), :action => 'lost_password' %>
</div>
</center>

@ -0,0 +1,14 @@
<center>
<div class="box login">
<h2><%=l(:label_password_lost)%></h2>
<%= start_form_tag %>
<p><label for="mail"><%=l(:field_mail)%> <span class="required">*</span></label><br/>
<%= text_field_tag 'mail', nil, :size => 40 %></p>
<p><center><%= submit_tag l(:button_submit) %></center></p>
<%= end_form_tag %>
</div>
</center>

@ -1,34 +1,34 @@
<h2><%=_('My account')%></h2>
<h2><%=l(:label_my_account)%></h2>
<p><%=_('Login')%>: <strong><%= @user.login %></strong><br />
<%=_('Created on')%>: <%= format_time(@user.created_on) %>,
<%=_('Last update')%>: <%= format_time(@user.updated_on) %></p>
<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />
<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>,
<%=l(:field_updated_on)%>: <%= format_time(@user.updated_on) %></p>
<%= error_messages_for 'user' %>
<div class="splitcontentleft">
<div class="box">
<h3><%=_('Information')%></h3>
<h3><%=l(:label_information_plural)%></h3>
&nbsp;
<%= start_form_tag :action => 'my_account' %>
<!--[form:user]-->
<p><label for="user_firstname"><%=_('Firstname')%> <span class="required">*</span></label><br/>
<p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label><br/>
<%= text_field 'user', 'firstname' %></p>
<p><label for="user_lastname"><%=_('Lastname')%> <span class="required">*</span></label><br/>
<p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label><br/>
<%= text_field 'user', 'lastname' %></p>
<p><label for="user_mail"><%=_('Mail')%> <span class="required">*</span></label><br/>
<%= text_field 'user', 'mail' %></p>
<p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label><br/>
<%= text_field 'user', 'mail' %></p>
<p><label for="user_language"><%=_('Language')%></label><br/>
<%= select("user", "language", Localization.langs) %></p>
<p><label for="user_language"><%=l(:field_language)%></label><br/>
<%= select("user", "language", Localization.langs.invert) %></p>
<!--[eoform:user]-->
<p><%= check_box 'user', 'mail_notification' %> <label for="user_mail_notification"><%=_('Mail notifications')%></label></p>
<p><%= check_box 'user', 'mail_notification' %> <label for="user_mail_notification"><%=l(:field_mail_notification)%></label></p>
<center><%= submit_tag _('Save') %></center>
<center><%= submit_tag l(:button_save) %></center>
<%= end_form_tag %>
</div>
</div>
@ -36,20 +36,20 @@
<div class="splitcontentright">
<div class="box">
<h3><%=_('Password')%></h3>
<h3><%=l(:field_password)%></h3>
&nbsp;
<%= start_form_tag :action => 'change_password' %>
<p><label for="password"><%=_('Password')%> <span class="required">*</span></label><br/>
<p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label><br/>
<%= password_field_tag 'password', nil, :size => 25 %></p>
<p><label for="new_password"><%=_('New password')%> <span class="required">*</span></label><br/>
<p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label><br/>
<%= password_field_tag 'new_password', nil, :size => 25 %></p>
<p><label for="new_password_confirmation"><%=_('Confirmation')%> <span class="required">*</span></label><br/>
<p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label><br/>
<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>
<center><%= submit_tag _('Save') %></center>
<center><%= submit_tag l(:button_save) %></center>
<%= end_form_tag %>
</div>
</div>

@ -1,19 +1,22 @@
<h2><%=_('My page') %></h2>
<h2><%=l(:label_my_page)%></h2>
<p>
<%=_('Welcome')%> <b><%= @user.firstname %></b><br />
<% unless @user.last_before_login_on.nil? %>
<%=_('Last login')%>: <%= format_time(@user.last_before_login_on) %>
<%=l(:label_last_login)%>: <%= format_time(@user.last_before_login_on) %>
<% end %>
</p>
<div class="splitcontentleft">
<h3><%=_('Reported issues')%></h3>
<h3><%=l(:label_reported_issues)%></h3>
<%= render :partial => 'issues/list_simple', :locals => { :issues => @reported_issues } %>
<%= "<p>(Last #{@reported_issues.length} updated)</p>" if @reported_issues.length > 0 %>
<% if @reported_issues.length > 0 %>
<p><%=lwr(:label_last_updates, @reported_issues.length)%></p>
<% end %>
</div>
<div class="splitcontentright">
<h3><%=_('Assigned to me')%></h3>
<h3><%=l(:label_assigned_to_me_issues)%></h3>
<%= render :partial => 'issues/list_simple', :locals => { :issues => @assigned_issues } %>
<%= "<p>(Last #{@assigned_issues.length} updated)</p>" if @assigned_issues.length > 0 %>
<% if @assigned_issues.length > 0 %>
<p><%=lwr(:label_last_updates, @assigned_issues.length)%></p>
<% end %>
</div>

@ -0,0 +1,21 @@
<center>
<div class="box login">
<h2><%=l(:label_password_lost)%></h2>
<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />
<%= error_messages_for 'user' %>
<%= start_form_tag :token => @token.value %>
<p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label><br/>
<%= password_field_tag 'new_password', nil, :size => 25 %></p>
<p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label><br/>
<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>
<p><center><%= submit_tag l(:button_save) %></center></p>
<%= end_form_tag %>
</div>
</center>

@ -0,0 +1,46 @@
<h2><%=l(:label_register)%></h2>
<%= start_form_tag %>
<%= error_messages_for 'user' %>
<div class="box">
<!--[form:user]-->
<p><label for="user_login"><%=l(:field_login)%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'login', :size => 25 %></p>
<p><label for="password"><%=l(:field_password)%></label> <span class="required">*</span><br/>
<%= password_field_tag 'password', nil, :size => 25 %></p>
<p><label for="password_confirmation"><%=l(:field_password_confirmation)%></label> <span class="required">*</span><br/>
<%= password_field_tag 'password_confirmation', nil, :size => 25 %></p>
<p><label for="user_firstname"><%=l(:field_firstname)%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'firstname' %></p>
<p><label for="user_lastname"><%=l(:field_lastname)%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'lastname' %></p>
<p><label for="user_mail"><%=l(:field_mail)%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'mail' %></p>
<p><label for="user_language"><%=l(:field_language)%></label><br/>
<%= select("user", "language", Localization.langs.invert) %></p>
<% for custom_value in @custom_values %>
<div style="float:left;margin-right:10px;">
<p><%= content_tag "label", custom_value.custom_field.name %>
<% if custom_value.custom_field.is_required? %><span class="required">*</span><% end %>
<br />
<%= custom_field_tag custom_value %></p>
</div>
<% end %>
<div style="clear: both;"></div>
<p><%= check_box 'user', 'mail_notification' %> <label for="user_mail_notification"><%=l(:field_mail_notification)%></label></p>
<!--[eoform:user]-->
</div>
<%= submit_tag l(:button_submit) %>
<%= end_form_tag %>

@ -2,10 +2,10 @@
<p>
<%= mail_to @user.mail %><br />
<%=_('Registered on')%>: <%= format_date(@user.created_on) %>
<%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
</p>
<h3><%=_('Projects')%></h3>
<h3><%=l(:label_project_plural)%></h3>
<p>
<% for membership in @user.memberships %>
<%= membership.project.name %> (<%= membership.role.name %>, <%= format_date(membership.created_on) %>)
@ -13,7 +13,7 @@
<% end %>
</p>
<h3><%=_('Activity')%></h3>
<h3><%=l(:label_activity)%></h3>
<p>
<%=_('Reported issues')%>: <%= Issue.count( [ "author_id=?", @user.id]) %>
<%=l(:label_reported_issues)%>: <%= Issue.count(["author_id=?", @user.id]) %>
</p>

@ -1,45 +1,50 @@
<h2><%=_('Administration')%></h2>
<h2><%=l(:label_administration)%></h2>
<p>
<%= image_tag "projects" %>
<%= link_to _('Projects'), :controller => 'admin', :action => 'projects' %> |
<%= link_to _('New'), :controller => 'projects', :action => 'add' %>
<%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> |
<%= link_to l(:label_new), :controller => 'projects', :action => 'add' %>
</p>
<p>
<%= image_tag "users" %>
<%= link_to _('Users'), :controller => 'users' %> |
<%= link_to _('New'), :controller => 'users', :action => 'add' %>
<%= link_to l(:label_user_plural), :controller => 'users' %> |
<%= link_to l(:label_new), :controller => 'users', :action => 'add' %>
</p>
<p>
<%= image_tag "role" %>
<%= link_to _('Roles and permissions'), :controller => 'roles' %>
<%= link_to l(:label_role_and_permissions), :controller => 'roles' %>
</p>
<p>
<%= image_tag "tracker" %>
<%= link_to _('Trackers'), :controller => 'trackers' %> |
<%= link_to _('Custom fields'), :controller => 'custom_fields' %>
<%= link_to l(:label_tracker_plural), :controller => 'trackers' %> |
<%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %>
</p>
<p>
<%= image_tag "workflow" %>
<%= link_to _('Issue Statuses'), :controller => 'issue_statuses' %> |
<%= link_to _('Workflow'), :controller => 'roles', :action => 'workflow' %>
<%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> |
<%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %>
</p>
<p>
<%= image_tag "options" %>
<%= link_to _('Enumerations'), :controller => 'enumerations' %>
<%= link_to l(:label_enumerations), :controller => 'enumerations' %>
</p>
<p>
<%= image_tag "mailer" %>
<%= link_to _('Mail notifications'), :controller => 'admin', :action => 'mail_options' %>
<%= link_to l(:field_mail_notification), :controller => 'admin', :action => 'mail_options' %>
</p>
<p>
<%= image_tag "login" %>
<%= link_to l(:label_authentication), :controller => 'auth_sources' %>
</p>
<p>
<%= image_tag "help" %>
<%= link_to _('Information'), :controller => 'admin', :action => 'info' %>
<%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %>
</p>

@ -1,8 +1,8 @@
<h2><%=_('Information')%></h2>
<p><%=_('Version')%>: <strong><%= RDM_APP_NAME %> <%= RDM_APP_VERSION %></strong></p>
<p><%=l(:field_version)%>: <strong><%= RDM_APP_NAME %> <%= RDM_APP_VERSION %></strong></p>
Environment:
<%=l(:label_environment)%>:
<ul>
<% Rails::Info.properties.each do |name, value| %>
<li><%= name %>: <%= value %></li>

@ -1,16 +1,16 @@
<h2><%=_('Mail notifications')%></h2>
<h2><%=l(:field_mail_notification)%></h2>
<p><%=_('Select actions for which mail notification should be enabled.')%></p>
<p><%=l(:text_select_mail_notifications)%></p>
<%= start_form_tag ({}, :id => 'mail_options_form')%>
<% for action in @actions %>
<%= check_box_tag "action_ids[]", action.id, action.mail_enabled? %>
<%= action.descr %><br />
<%= action.description %><br />
<% end %>
<br />
<p>
<a href="javascript:checkAll('mail_options_form', true)"><%=_('Check all')%></a> |
<a href="javascript:checkAll('mail_options_form', false)"><%=_('Uncheck all')%></a>
<a href="javascript:checkAll('mail_options_form', true)"><%=l(:button_check_all)%></a> |
<a href="javascript:checkAll('mail_options_form', false)"><%=l(:button_uncheck_all)%></a>
</p>
<%= submit_tag _('Save') %>
<%= submit_tag l(:button_save) %>
<%= end_form_tag %>

@ -1,25 +1,25 @@
<h2><%=_('Projects')%></h2>
<h2><%=l(:label_project_plural)%></h2>
<table width="100%" cellspacing="1" cellpadding="2" class="listTableContent">
<tr class="ListHead">
<%= sort_header_tag('name', :caption => _('Project')) %>
<th><%=_('Description')%></th>
<th><%=_('Public')%></th>
<th><%=_('Subprojects')%></th>
<%= sort_header_tag('created_on', :caption => _('Created on')) %>
<%= sort_header_tag('name', :caption => l(:label_project)) %>
<th><%=l(:field_description)%></th>
<th><%=l(:field_is_public)%></th>
<th><%=l(:label_subproject_plural)%></th>
<%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
<th></th>
</tr>
<% for project in @projects %>
<tr class="<%= cycle("odd", "even") %>">
<td><%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %>
<td><%= project.descr %>
<td><%= project.description %>
<td align="center"><%= image_tag 'true' if project.is_public? %>
<td align="center"><%= project.projects_count %>
<td align="center"><%= format_date(project.created_on) %>
<td align="center">
<%= start_form_tag({:controller => 'projects', :action => 'destroy', :id => project}) %>
<%= submit_tag _('Delete'), :class => "button-small" %>
<%= submit_tag l(:button_delete), :class => "button-small" %>
<%= end_form_tag %>
</td>
</tr>
@ -29,4 +29,4 @@
<p><%= pagination_links_full @project_pages %>
[ <%= @project_pages.current.first_item %> - <%= @project_pages.current.last_item %> / <%= @project_count %> ]</p>
<p><%= link_to ('&#187; ' + _('New project')), :controller => 'projects', :action => 'add' %></p>
<p><%= link_to ('&#187; ' + l(:label_project_new)), :controller => 'projects', :action => 'add' %></p>

@ -0,0 +1,49 @@
<%= error_messages_for 'auth_source' %>
<div class="box">
<!--[form:auth_source]-->
<p><label for="auth_source_name"><%=l(:field_name)%></label> <span class="required">*</span><br/>
<%= text_field 'auth_source', 'name' %></p>
<p><label for="auth_source_host"><%=l(:field_host)%></label> <span class="required">*</span><br/>
<%= text_field 'auth_source', 'host' %></p>
<p><label for="auth_source_port"><%=l(:field_port)%></label> <span class="required">*</span><br/>
<%= text_field 'auth_source', 'port', :size => 6 %></p>
<p><label for="auth_source_account"><%=l(:field_account)%></label><br/>
<%= text_field 'auth_source', 'account' %></p>
<p><label for="auth_source_account_password"><%=l(:field_password)%></label><br/>
<%= password_field 'auth_source', 'account_password' %></p>
<p><label for="auth_source_base_dn"><%=l(:field_base_dn)%></label> <span class="required">*</span><br/>
<%= text_field 'auth_source', 'base_dn', :size => 60 %></p>
<p><%= check_box 'auth_source', 'onthefly_register' %>
<label for="auth_source_onthefly_register"><%=l(:field_onthefly)%></label></p>
<fieldset><legend><%=l(:label_attribute_plural)%></legend>
<div style="float:left;margin-right:10px;">
<p><label for="auth_source_attr_login"><%=l(:field_login)%></label> <span class="required">*</span><br/>
<%= text_field 'auth_source', 'attr_login', :size => 20 %></p>
</div>
<div style="float:left;margin-right:10px;">
<p><label for="auth_source_attr_firstname"><%=l(:field_firstname)%></label><br/>
<%= text_field 'auth_source', 'attr_firstname', :size => 20 %></p>
</div>
<div style="float:left;margin-right:10px;">
<p><label for="auth_source_attr_lastname"><%=l(:field_lastname)%></label><br/>
<%= text_field 'auth_source', 'attr_lastname', :size => 20 %></p>
</div>
<div>
<p><label for="auth_source_attr_mail"><%=l(:field_mail)%></label><br/>
<%= text_field 'auth_source', 'attr_mail', :size => 20 %></p>
</div>
</fieldset>
<!--[eoform:auth_source]-->
</div>

@ -0,0 +1,7 @@
<h2><%=l(:label_auth_source)%> (<%= @auth_source.auth_method_name %>)</h2>
<%= start_form_tag :action => 'update', :id => @auth_source %>
<%= render :partial => 'form' %>
<%= submit_tag l(:button_save) %>
<%= end_form_tag %>

@ -0,0 +1,32 @@
<h2><%=l(:label_auth_source_plural)%></h2>
<table border="0" cellspacing="1" cellpadding="2" class="listTableContent">
<tr class="ListHead">
<td><%=l(:field_name)%></td>
<td><%=l(:field_type)%></td>
<td><%=l(:field_host)%></td>
<td></td>
<td></td>
</tr>
<% for source in @auth_sources %>
<tr class="<%= cycle("odd", "even") %>">
<td><%= link_to source.name, :action => 'edit', :id => source%></td>
<td align="center"><%= source.auth_method_name %></td>
<td align="center"><%= source.host %></td>
<td align="center">
<%= link_to l(:button_test), :action => 'test_connection', :id => source %>
</td>
<td align="center">
<%= start_form_tag :action => 'destroy', :id => source %>
<%= submit_tag l(:button_delete), :class => "button-small" %>
<%= end_form_tag %>
</td>
</tr>
<% end %>
</table>
<%= pagination_links_full @auth_source_pages %>
<br />
<%= link_to '&#187; ' + l(:label_auth_source_new), :action => 'new' %>

@ -0,0 +1,6 @@
<h2><%=l(:label_auth_source_new)%> (<%= @auth_source.auth_method_name %>)</h2>
<%= start_form_tag :action => 'create' %>
<%= render :partial => 'form' %>
<%= submit_tag l(:button_create) %>
<%= end_form_tag %>

@ -1,26 +1,53 @@
<%= error_messages_for 'custom_field' %>
<!--[form:custom_field]-->
<p><label for="custom_field_name"><%=_('Name')%></label><br/>
<%= text_field 'custom_field', 'name' %></p>
<div class="box">
<p><label for="custom_field_name"><%=l(:field_name)%></label> <span class="required">*</span><br/>
<%= text_field 'custom_field', 'name' %></p>
<p><label for="custom_field_typ"><%=_('Type')%></label><br/>
<%= select("custom_field", "typ", CustomField::TYPES) %></p>
<p><label for="custom_field_typ"><%=l(:field_field_format)%></label><br/>
<%= select("custom_field", "field_format", custom_field_formats_for_select) %></p>
<p><%= check_box 'custom_field', 'is_required' %>
<label for="custom_field_is_required"><%=_('Required')%></label></p>
<p><%= check_box 'custom_field', 'is_for_all' %>
<label for="custom_field_is_for_all"><%=_('For all projects')%></label></p>
<p><label for="custom_field_min_length"><%=_('Min - max length')%></label> (<%=_('0 means no restriction')%>)<br/>
<p><label for="custom_field_min_length"><%=l(:label_min_max_length)%></label> (<%=l(:text_min_max_length_info)%>)<br/>
<%= text_field 'custom_field', 'min_length', :size => 5 %> -
<%= text_field 'custom_field', 'max_length', :size => 5 %></p>
<p><label for="custom_field_regexp"><%=_('Regular expression pattern')%></label> (eg. ^[A-Z0-9]+$)<br/>
<p><label for="custom_field_regexp"><%=l(:field_regexp)%></label> (<%=l(:text_regexp_info)%>)<br/>
<%= text_field 'custom_field', 'regexp', :size => 50 %></p>
<p><label for="custom_field_possible_values"><%=_('Possible values')%></label> (separator: |)<br/>
<%= text_area 'custom_field', 'possible_values', :rows => 5, :cols => 60 %></p>
<p><label for="custom_field_possible_values"><%=l(:field_possible_values)%></label> (<%=l(:text_possible_values_info)%>)<br/>
<%= text_area 'custom_field', 'possible_values', :rows => 5, :cols => 60 %></p>
</div>
<!--[eoform:custom_field]-->
<div class="box">
<% case type.to_s
when "IssueCustomField" %>
<fieldset><legend><%=l(:label_tracker_plural)%></legend>
<% for tracker in @trackers %>
<input type="checkbox"
name="tracker_ids[]"
value="<%= tracker.id %>"
<%if @custom_field.trackers.include? tracker%>checked="checked"<%end%>
> <%= tracker.name %>
<% end %></fieldset>
&nbsp;
<p><%= check_box 'custom_field', 'is_required' %>
<label for="custom_field_is_required"><%=l(:field_is_required)%></label></p>
<p><%= check_box 'custom_field', 'is_for_all' %>
<label for="custom_field_is_for_all"><%=l(:field_is_for_all)%></label></p>
<% when "UserCustomField" %>
<p><%= check_box 'custom_field', 'is_required' %>
<label for="custom_field_is_required"><%=l(:field_is_required)%></label></p>
<% when "ProjectCustomField" %>
<p><%= check_box 'custom_field', 'is_required' %>
<label for="custom_field_is_required"><%=l(:field_is_required)%></label></p>
<% end %>
</div>

@ -1,6 +1,6 @@
<h2><%=_('Custom field')%></h2>
<h2><%=l(:label_custom_field)%> (<%=l(@custom_field.type_name)%>)</h2>
<%= start_form_tag :action => 'edit', :id => @custom_field %>
<%= render :partial => 'form' %>
<%= submit_tag _('Save') %>
<%= render :partial => 'form', :locals => { :type => @custom_field.type } %>
<%= submit_tag l(:button_save) %>
<%= end_form_tag %>

@ -1,32 +1,37 @@
<h2><%=_('Custom fields')%></h2>
<h2><%=l(:label_custom_field_plural)%></h2>
<table border="0" cellspacing="1" cellpadding="2" class="listTableContent">
<tr class="ListHead">
<th><%=_('Name')%></th>
<th><%=_('Type')%></th>
<th><%=_('Required')%></th>
<th><%=_('For all projects')%></th>
<th><%=l(:field_name)%></th>
<th><%=l(:field_type)%></th>
<th><%=l(:field_field_format)%></th>
<th><%=l(:field_is_required)%></th>
<th><%=l(:field_is_for_all)%></th>
<th><%=_('Used by')%></th>
<th></th>
</tr>
<% for custom_field in @custom_fields %>
<tr class="<%= cycle("odd", "even") %>">
<td><%= link_to custom_field.name, :action => 'edit', :id => custom_field %></td>
<td align="center"><%= CustomField::TYPES[custom_field.typ][0] %></td>
<td align="center"><%= l(custom_field.type_name) %></td>
<td align="center"><%= l(CustomField::FIELD_FORMATS[custom_field.field_format]) %></td>
<td align="center"><%= image_tag 'true' if custom_field.is_required? %></td>
<td align="center"><%= image_tag 'true' if custom_field.is_for_all? %></td>
<td align="center"><%= custom_field.projects.count.to_s + ' ' + _('Project') + '(s)' unless custom_field.is_for_all? %></td>
<td align="center"><%= custom_field.projects.count.to_s + ' ' + lwr(:label_project, custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %></td>
<td align="center">
<%= start_form_tag :action => 'destroy', :id => custom_field %>
<%= submit_tag _('Delete'), :class => "button-small" %>
<%= submit_tag l(:button_delete), :class => "button-small" %>
<%= end_form_tag %> </td>
</tr>
<% end %>
</table>
<%= link_to ('&#171; ' + _('Previous')), { :page => @custom_field_pages.current.previous } if @custom_field_pages.current.previous %>
<%= link_to (_('Next') + ' &#187;'), { :page => @custom_field_pages.current.next } if @custom_field_pages.current.next %>
<%= pagination_links_full @custom_field_pages %>
<br />
<%= link_to ('&#187; ' + _('New custom field')), :action => 'new' %>
<%=l(:label_custom_field_new)%>:
<ul>
<li><%= link_to l(:label_issue_plural), :action => 'new', :type => 'IssueCustomField' %></li>
<li><%= link_to l(:label_project_plural), :action => 'new', :type => 'ProjectCustomField' %></li>
<li><%= link_to l(:label_user_plural), :action => 'new', :type => 'UserCustomField' %></li>
</ul>

@ -1,7 +1,8 @@
<h2><%=_('New custom field')%></h2>
<h2><%=l(:label_custom_field_new)%> (<%=l(@custom_field.type_name)%>)</h2>
<%= start_form_tag :action => 'new' %>
<%= render :partial => 'form' %>
<%= submit_tag _('Create') %>
<%= render :partial => 'form', :locals => { :type => @custom_field.type } %>
<%= hidden_field_tag 'type', @custom_field.type %>
<%= submit_tag l(:button_save) %>
<%= end_form_tag %>

@ -1,15 +1,15 @@
<%= error_messages_for 'document' %>
<!--[form:document]-->
<p><label for="document_category_id"><%=_('Category')%></label><br />
<p><label for="document_category_id"><%=l(:field_category)%></label><br />
<select name="document[category_id]">
<%= options_from_collection_for_select @categories, "id", "name",@document.category_id %>
<%= options_from_collection_for_select @categories, "id", "name", @document.category_id %>
</select></p>
<p><label for="document_title"><%=_('Title')%> <span class="required">*</span></label><br />
<p><label for="document_title"><%=l(:field_title)%> <span class="required">*</span></label><br />
<%= text_field 'document', 'title', :size => 60 %></p>
<p><label for="document_descr"><%=_('Description')%> <span class="required">*</span></label><br />
<%= text_area 'document', 'descr', :cols => 60, :rows => 5 %></p>
<p><label for="document_description"><%=l(:field_description)%> <span class="required">*</span></label><br />
<%= text_area 'document', 'description', :cols => 60, :rows => 5 %></p>
<!--[eoform:document]-->

@ -1,6 +1,6 @@
<h2><%= @document.title %></h2>
<strong><%=_('Description')%>:</strong> <%= @document.descr %><br />
<strong><%=_('Description')%>:</strong> <%= @document.description %><br />
<strong><%=_('Category')%>:</strong> <%= @document.category.name %><br />
<br />

@ -5,7 +5,8 @@
<%= hidden_field_tag 'confirm', 1 %>
<%= hidden_field 'history', 'status_id' %>
<div class="box">
<p><%=_('New status')%>: <b><%= @history.status.name %></b></p>
<div>
@ -24,6 +25,8 @@
<p><label for="history_notes"><%=_('Notes')%></label><br />
<%= text_area 'history', 'notes', :cols => 60, :rows => 10 %></p>
</div>
<%= submit_tag _('Save') %>
<%= end_form_tag %>

@ -1,18 +1,12 @@
<h2><%=_('Issue')%> #<%= @issue.id %></h2>
<h2><%=_@issue.tracker.name%> #<%= @issue.id %> - <%= @issue.subject %></h2>
<%= error_messages_for 'issue' %>
<%= start_form_tag :action => 'edit', :id => @issue %>
<div class="box">
<!--[form:issue]-->
<p><%=_('Status')%>: <b><%= @issue.status.name %></b></p>
<div style="float:left;margin-right:10px;">
<p><label for="issue_tracker_id"><%=_('Tracker')%> <span class="required">*</span></label><br/>
<select name="issue[tracker_id]">
<%= options_from_collection_for_select @trackers, "id", "name", @issue.tracker_id %></p>
</select></p>
</div>
<div style="float:left;margin-right:10px;">
<p><label for="issue_priority_id"><%=_('Priority')%> <span class="required">*</span></label><br/>
<select name="issue[priority_id]">
@ -39,24 +33,21 @@
<p><label for="issue_subject"><%=_('Subject')%></label><span class="required">*</span><br/>
<%= text_field 'issue', 'subject', :size => 60 %></p>
<p><label for="issue_descr"><%=_('Description')%></label><span class="required">*</span><br/>
<%= text_area 'issue', 'descr', :cols => 60, :rows => 10 %></p>
<p><label for="issue_description"><%=_('Description')%></label><span class="required">*</span><br/>
<%= text_area 'issue', 'description', :cols => 60, :rows => 10 %></p>
<% for custom_value in @custom_values %>
<p><%= content_tag "label", custom_value.custom_field.name %>
<% if custom_value.custom_field.is_required? %><span class="required">*</span><% end %>
<br />
<%= custom_field_tag custom_value %></p>
<% for custom_value in @custom_values %>
<p><%= custom_field_tag_with_label custom_value %></p>
<% end %>
<p><label for="issue_fixed_version"><%=_('Fixed in version')%></label><br/>
<select name="issue[fixed_version_id]">
<option value="">--none--</option>
<%= options_from_collection_for_select @project.versions, "id", "name", @issue.fixed_version_id %>
</select></p>
<!--[eoform:issue]-->
</div>
<center><%= submit_tag _('Save') %></center>
<%= submit_tag _('Save') %>
<%= end_form_tag %>

@ -1,18 +1,21 @@
<h2><%=_('Issue')%> #<%= @issue.id %> - <%= @issue.subject %></h2>
<h2><%=_(@issue.tracker.name)%> #<%= @issue.id %> - <%= @issue.subject %></h2>
<div class="box">
<p><b><%=_('Tracker')%>:</b> <%= @issue.tracker.name %></p>
<p><b><%=_('Status')%>:</b> <%= @issue.status.name %></p>
<p><b><%=_('Priority')%>:</b> <%= @issue.priority.name %></p>
<p><b><%=_('Category')%>:</b> <%= @issue.category.name unless @issue.category_id.nil? %></p>
<p><b><%=_('Status')%>:</b> <%= @issue.status.name %></p>
<p><b><%=_('Author')%>:</b> <%= @issue.author.display_name %></p>
<p><b><%=_('Assigned to')%>:</b> <%= @issue.assigned_to.display_name unless @issue.assigned_to.nil? %></p>
<p><b><%=_('Subject')%>:</b> <%= @issue.subject %></p>
<p><b><%=_('Description')%>:</b> <%= simple_format auto_link @issue.descr %></p>
<p><b><%=_('Description')%>:</b> <%= simple_format auto_link @issue.description %></p>
<p><b><%=_('Created on')%>:</b> <%= format_date(@issue.created_on) %></p>
<% for custom_value in @custom_values %>
<p><b><%= custom_value.custom_field.name %></b>: <%= show_value custom_value %></p>
<% end %>
<% if authorize_for('issues', 'edit') %>
<%= start_form_tag ({:controller => 'issues', :action => 'edit', :id => @issue}, :method => "get" ) %>
<%= submit_tag _('Edit') %>

@ -1,13 +1,51 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<title>redMine</title>
<title><%= $RDM_HEADER_TITLE %></title>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<meta name="description" content="redMine" />
<meta name="keywords" content="issue,bug,tracker" />
<%= stylesheet_link_tag "application" %>
<%= stylesheet_link_tag "menu" %>
<%= stylesheet_link_tag "rails" %>
<%= javascript_include_tag :defaults %>
<%= javascript_include_tag 'menu' %>
<script type='text/javascript'>
var menu_contenu=' \
<div id="menuAdmin" class="menu" onmouseover="menuMouseover(event)"> \
<a class="menuItem" href="\/admin\/projects" onmouseover="menuItemMouseover(event,\'menuProjects\');"><span class="menuItemText"><%=_('Projects')%><\/span><span class="menuItemArrow">&#9654;<\/span><\/a> \
<a class="menuItem" href="\/users" onmouseover="menuItemMouseover(event,\'menuUsers\');"><span class="menuItemText"><%=_('Users')%><\/span><span class="menuItemArrow">&#9654;<\/span><\/a> \
<a class="menuItem" href="\/roles"><%=_('Roles and permissions')%><\/a> \
<a class="menuItem" href="\/trackers" onmouseover="menuItemMouseover(event,\'menuTrackers\');"><span class="menuItemText"><%=_('Trackers')%><\/span><span class="menuItemArrow">&#9654;<\/span><\/a> \
<a class="menuItem" href="\/custom_fields"><%=_('Custom fields')%><\/a> \
<a class="menuItem" href="\/enumerations"><%=_('Enumerations')%><\/a> \
<a class="menuItem" href="\/admin\/mail_options"><%=_('Mail notifications')%><\/a> \
<a class="menuItem" href="\/auth_sources"><%=l(:label_authentication)%><\/a> \
<a class="menuItem" href="\/admin\/info"><%=_('Information')%><\/a> \
<\/div> \
<div id="menuTrackers" class="menu"> \
<a class="menuItem" href="\/issue_statuses"><%=_('Issue Statuses')%><\/a> \
<a class="menuItem" href="\/roles\/workflow"><%=_('Workflow')%><\/a> \
<\/div> \
<div id="menuProjects" class="menu"><a class="menuItem" href="\/projects\/add"><%=_('New')%><\/a><\/div> \
<div id="menuUsers" class="menu"><a class="menuItem" href="\/users\/add"><%=_('New')%><\/a><\/div> \
\
<% unless @project.nil? || @project.id.nil? %> \
<div id="menuProject" class="menu" onmouseover="menuMouseover(event)"> \
<%= link_to _('Issues'), {:controller => 'projects', :action => 'list_issues', :id => @project }, :class => "menuItem" %> \
<%= link_to _('Reports'), {:controller => 'reports', :action => 'issue_report', :id => @project }, :class => "menuItem" %> \
<%= link_to _('News'), {:controller => 'projects', :action => 'list_news', :id => @project }, :class => "menuItem" %> \
<%= link_to _('Change log'), {:controller => 'projects', :action => 'changelog', :id => @project }, :class => "menuItem" %> \
<%= link_to _('Documents'), {:controller => 'projects', :action => 'list_documents', :id => @project }, :class => "menuItem" %> \
<%= link_to _('Members'), {:controller => 'projects', :action => 'list_members', :id => @project }, :class => "menuItem" %> \
<%= link_to _('Files'), {:controller => 'projects', :action => 'list_files', :id => @project }, :class => "menuItem" %> \
<%= link_to_if_authorized _('Settings'), {:controller => 'projects', :action => 'settings', :id => @project }, :class => "menuItem" %> \
<\/div> \
<% end %> \
';
</script>
</head>
<body>
@ -15,37 +53,42 @@
<div id="header">
<div style="float: left;">
<h1><%= RDM_APP_NAME %></h1>
<h2>Project management</h2>
<h1><%= $RDM_HEADER_TITLE %></h1>
<h2><%= $RDM_HEADER_SUBTITLE %></h2>
</div>
<div style="float: right; padding-right: 1em; padding-top: 0.2em;">
<% unless session[:user].nil? %><small><%=_('Logged as')%> <b><%= session[:user].login %></b></small><% end %>
<% if loggedin? %><small><%=l(:label_logged_as)%> <b><%= @logged_in_user.login %></b></small><% end %>
</div>
</div>
<div id="navigation">
<ul>
<li class="selected"><%= link_to _('Home'), { :controller => '' }, :class => "picHome" %></li>
<li><%= link_to _('My page'), { :controller => 'account', :action => 'my_page'}, :class => "picUserPage" %></li>
<li><%= link_to _('Projects'), { :controller => 'projects' }, :class => "picProject" %></li>
<li class="selected"><%= link_to l(:label_home), { :controller => '' }, :class => "picHome" %></li>
<li><%= link_to l(:label_my_page), { :controller => 'account', :action => 'my_page'}, :class => "picUserPage" %></li>
<li><%= link_to l(:label_project_plural), { :controller => 'projects' }, :class => "picProject" %></li>
<% unless session[:user].nil? %>
<li><%= link_to _('My account'), { :controller => 'account', :action => 'my_account' }, :class => "picUser" %></li>
<% end %>
<% unless @project.nil? || @project.id.nil? %>
<li><%= link_to @project.name, { :controller => 'projects', :action => 'show', :id => @project }, :class => "picProject", :onmouseover => "buttonMouseover(event, 'menuProject');" %></li>
<% end %>
<% if admin_loggedin? %>
<li><%= link_to _('Administration'), { :controller => 'admin' }, :class => "picAdmin" %></li>
<% end %>
<% if loggedin? %>
<li><%= link_to l(:label_my_account), { :controller => 'account', :action => 'my_account' }, :class => "picUser" %></li>
<% end %>
<li class="right"><%= link_to _('Help'), { :controller => 'help', :ctrl => @params[:controller], :page => @params[:action] }, :target => "new", :class => "picHelp" %></li>
<% if session[:user].nil? %>
<li class="right"><%= link_to _('Log in'), { :controller => 'account', :action => 'login' }, :class => "picUser" %></li>
<% else %>
<li class="right"><%= link_to _('Logout'), { :controller => 'account', :action => 'logout' }, :class => "picUser" %></li>
<% end %>
</ul>
<% if admin_loggedin? %>
<li><%= link_to l(:label_administration), { :controller => 'admin' }, :class => "picAdmin", :onmouseover => "buttonMouseover(event, 'menuAdmin');" %></li>
<% end %>
<li class="right"><%= link_to l(:label_help), { :controller => 'help', :ctrl => @params[:controller], :page => @params[:action] }, :target => "new", :class => "picHelp" %></li>
<% if loggedin? %>
<li class="right"><%= link_to l(:label_logout), { :controller => 'account', :action => 'logout' }, :class => "picUser" %></li>
<% else %>
<li class="right"><%= link_to l(:label_login), { :controller => 'account', :action => 'login' }, :class => "picUser" %></li>
<% end %>
</ul>
</div>
<script type='text/javascript'>if(document.getElementById) {document.write(menu_contenu);}</script>
<div id="subcontent">
@ -64,15 +107,14 @@
</ul>
<% end %>
<% unless session[:user].nil? %>
<% if loggedin? and @logged_in_user.memberships.length > 0 %>
<h2><%=_('My projects') %></h2>
<ul class="menublock">
<% for membership in session[:user].memberships %>
<% for membership in @logged_in_user.memberships %>
<li><%= link_to membership.project.name, :controller => 'projects', :action => 'show', :id => membership.project %></li>
<% end %>
</ul>
<% end %>
<% end %>
</div>
<div id="content">
@ -81,7 +123,10 @@
</div>
<div id="footer">
<p><a href="http://redmine.org/" target="_new"><%= RDM_APP_NAME %></a> <%= RDM_APP_VERSION %></p>
<p>
<%= auto_link $RDM_FOOTER_SIG %> |
<a href="http://redmine.org/" target="_new"><%= RDM_APP_NAME %></a> <%= RDM_APP_VERSION %>
</p>
</div>
</div>

@ -1,6 +1,6 @@
<%=_('Issue')%> #<%= issue.id %> - <%= issue.subject %>
<%=_('Author')%>: <%= issue.author.display_name %>
<%= issue.descr %>
<%= issue.description %>
http://<%= RDM_HOST_NAME %>/issues/show/<%= issue.id %>
http://<%= $RDM_HOST_NAME %>/issues/show/<%= issue.id %>

@ -0,0 +1,3 @@
Une nouvelle demande (#<%= @issue.id %>) a été soumise.
----------------------------------------
<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>

@ -0,0 +1,3 @@
La demande #<%= @issue.id %> a été mise à jour au statut "<%= @issue.status.name %>".
----------------------------------------
<%= render :file => "_issue", :use_full_path => true, :locals => { :issue => @issue } %>

@ -0,0 +1,3 @@
To change your password, use the following link:
http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %>

@ -0,0 +1,3 @@
Pour changer votre mot de passe, utilisez le lien suivant:
http://<%= $RDM_HOST_NAME %>/account/lost_password?token=<%= @token.value %>

@ -0,0 +1,3 @@
To activate your redMine account, use the following link:
http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %>

@ -0,0 +1,3 @@
Pour activer votre compte sur redMine, utilisez le lien suivant:
http://<%= $RDM_HOST_NAME %>/account/register?token=<%= @token.value %>

@ -4,10 +4,10 @@
<p><label for="news_title"><%=_('Title')%></label> <span class="required">*</span><br/>
<%= text_field 'news', 'title', :size => 60 %></p>
<p><label for="news_shortdescr"><%=_('Summary')%> <span class="required">*</span></label><br/>
<%= text_area 'news', 'shortdescr', :cols => 60, :rows => 2 %></p>
<p><label for="news_summary"><%=_('Summary')%></label><br/>
<%= text_area 'news', 'summary', :cols => 60, :rows => 2 %></p>
<p><label for="news_descr"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'news', 'descr', :cols => 60, :rows => 10 %></p>
<p><label for="news_description"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'news', 'description', :cols => 60, :rows => 10 %></p>
<!--[eoform:news]-->

@ -1,10 +1,10 @@
<h2><%= @news.title %></h2>
<p>
<b><%=_('Summary')%></b>: <%= @news.shortdescr %><br />
<b><%=_('Summary')%></b>: <%= @news.summary %><br />
<b><%=_('By')%></b>: <%= @news.author.display_name %><br />
<b><%=_('Date')%></b>: <%= format_time(@news.created_on) %>
</p>
<%= simple_format auto_link @news.descr %>
<%= simple_format auto_link @news.description %>

@ -1,10 +1,11 @@
<%= error_messages_for 'project' %>
<div class="box">
<!--[form:project]-->
<p><label for="project_name"><%=_('Name')%> <span class="required">*</span></label><br/>
<%= text_field 'project', 'name' %></p>
<% if session[:user].admin %>
<% if admin_loggedin? %>
<p><label for="project_parent_id"><%=_('Subproject of')%></label><br/>
<select name="project[parent_id]">
<option value=""></option>
@ -12,15 +13,19 @@
</select></p>
<% end %>
<p><label for="project_descr"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'project', 'descr', :cols => 60, :rows => 3 %></p>
<p><label for="project_description"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'project', 'description', :cols => 60, :rows => 3 %></p>
<p><label for="project_homepage"><%=_('Homepage')%></label><br/>
<%= text_field 'project', 'homepage', :size => 40 %></p>
<p><%= check_box 'project', 'is_public' %>
<label for="project_is_public"><%=_('Public')%></label></p>
<% for custom_value in @custom_values %>
<p><%= custom_field_tag_with_label custom_value %></p>
<% end %>
<fieldset><legend><%=_('Custom fields')%></legend>
<% for custom_field in @custom_fields %>
<input type="checkbox"
@ -31,6 +36,6 @@
> <%= custom_field.name %>
<% end %></fieldset>
<br />
</div>
<!--[eoform:project]-->

@ -4,4 +4,3 @@
<%= render :partial => 'form' %>
<%= submit_tag _('Create') %>
<%= end_form_tag %>

@ -12,8 +12,8 @@
<p><label for="document_title"><%=_('Title')%> <span class="required">*</span></label><br />
<%= text_field 'document', 'title', :size => 60 %></p>
<p><label for="document_descr"><%=_('Description')%> <span class="required">*</span></label><br />
<%= text_area 'document', 'descr', :cols => 60, :rows => 5 %></p>
<p><label for="document_description"><%=_('Description')%> <span class="required">*</span></label><br />
<%= text_area 'document', 'description', :cols => 60, :rows => 5 %></p>
<p><label for="attachment_file"><%=_('File')%></label><br/>
<%= file_field 'attachment', 'file' %></p>

@ -1,16 +1,12 @@
<h2><%=_('New issue')%></h2>
<h2><%=_('New issue')%>: <%=_(@tracker.name)%></h2>
<%= start_form_tag( { :action => 'add_issue', :id => @project }, :multipart => true) %>
<%= error_messages_for 'issue' %>
<div class="box">
<!--[form:issue]-->
<div style="float:left;margin-right:10px;">
<p><label for="issue_tracker_id"><%=_('Tracker')%> <span class="required">*</span></label><br/>
<select name="issue[tracker_id]">
<%= options_from_collection_for_select @trackers, "id", "name", @issue.tracker_id %></p>
</select></p>
</div>
<%= hidden_field_tag 'tracker_id', @tracker.id %>
<div style="float:left;margin-right:10px;">
<p><label for="issue_priority_id"><%=_('Priority')%> <span class="required">*</span></label><br/>
@ -30,33 +26,26 @@
<div>
<p><label for="issue_category_id"><%=_('Category')%></label><br/>
<select name="issue[category_id]">
<option value=""></option>
<%= options_from_collection_for_select @project.issue_categories, "id", "name", @issue.category_id %></p>
<option value=""></option><%= options_from_collection_for_select @project.issue_categories, "id", "name", @issue.category_id %>
</select></p>
</div>
<p><label for="issue_subject"><%=_('Subject')%> <span class="required">*</span></label><br/>
<%= text_field 'issue', 'subject', :size => 80 %></p>
<p><label for="issue_descr"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'issue', 'descr', :cols => 60, :rows => 10 %></p>
<p><label for="issue_description"><%=_('Description')%> <span class="required">*</span></label><br/>
<%= text_area 'issue', 'description', :cols => 60, :rows => 10 %></p>
<% for custom_value in @custom_values %>
<div style="float:left;margin-right:10px;">
<p><%= content_tag "label", custom_value.custom_field.name %>
<% if custom_value.custom_field.is_required? %><span class="required">*</span><% end %>
<br />
<%= custom_field_tag custom_value %></p>
</div>
<% for custom_value in @custom_values %>
<p><%= custom_field_tag_with_label custom_value %></p>
<% end %>
<div style="clear: both;">
<p><label for="attachment_file"><%=_('Attachment')%></label><br/>
<%= file_field 'attachment', 'file' %></p>
</div>
<!--[eoform:issue]-->
</div>
<%= submit_tag _('Create') %>
<%= end_form_tag %>

@ -3,7 +3,7 @@
<% fixed_issues = @fixed_issues.group_by {|i| i.fixed_version } %>
<% fixed_issues.each do |version, issues| %>
<p><strong><%= version.name %></strong> - <%= format_date(version.effective_date) %><br />
<%=h version.descr %></p>
<%=h version.description %></p>
<ul>
<% issues.each do |i| %>
<li><%= link_to i.long_id, :controller => 'issues', :action => 'show', :id => i %> [<%= i.tracker.name %>]: <%= i.subject %></li>

@ -10,7 +10,7 @@
<% for project in @projects %>
<tr class="<%= cycle("odd", "even") %>">
<td><%= link_to project.name, :action => 'show', :id => project %>
<td><%= project.descr %>
<td><%= project.description %>
<td align="center"><%= format_date(project.created_on) %>
</tr>
<% end %>

@ -8,7 +8,7 @@
<li>
<b><%= link_to d.title, :controller => 'documents', :action => 'show', :id => d %></b>
<br />
<%=_('Desciption')%>: <%= d.descr %><br />
<%=_('Desciption')%>: <%= d.description %><br />
<%= format_time(d.created_on) %>
</li>

@ -7,6 +7,7 @@
<td><small><%=_('Tracker')%>:</small><br /><%= search_filter_tag 'tracker_id', :class => 'select-small' %></td>
<td><small><%=_('Priority')%>:</small><br /><%= search_filter_tag 'priority_id', :class => 'select-small' %></td>
<td><small><%=_('Category')%>:</small><br /><%= search_filter_tag 'category_id', :class => 'select-small' %></td>
<td><small><%=_('Fixed in version')%>:</small><br /><%= search_filter_tag 'fixed_version_id', :class => 'select-small' %></td>
<td><small><%=_('Assigned to')%>:</small><br /><%= search_filter_tag 'assigned_to_id', :class => 'select-small' %></td>
<td><small><%=_('Subprojects')%>:</small><br /><%= search_filter_tag 'subproject_id', :class => 'select-small' %></td>
@ -52,9 +53,4 @@
<p>
<%= pagination_links_full @issue_pages %>
[ <%= @issue_pages.current.first_item %> - <%= @issue_pages.current.last_item %> / <%= @issue_count %> ]
</p>
<p>
<%= link_to_if_authorized '&#187; ' + _('Report an issue'), :controller => 'projects', :action => 'add_issue', :id => @project %>
</p>
</p>

@ -6,7 +6,7 @@
<%= link_to_if_authorized image_tag('edit_small'), :controller => 'news', :action => 'edit', :id => news %>
<%= link_to_if_authorized image_tag('delete'), { :controller => 'news', :action => 'destroy', :id => news }, :confirm => 'Are you sure?' %>
<br />
<%= news.shortdescr %>
<%= news.summary %>
<small>[<%= link_to _('Read...'), :controller => 'news', :action => 'show', :id => news %>]</small>
</p>
<% end %>

@ -1,11 +1,11 @@
<h2><%=_('Settings')%></h2>
<div class="box">
<%= start_form_tag :action => 'edit', :id => @project %>
<%= render :partial => 'form' %>
<center><%= submit_tag _('Save') %></center>
<%= end_form_tag %>
</div>
&nbsp;
<div class="box">
<h3><%=_('Members')%></h3>
@ -54,7 +54,7 @@
<% for version in @project.versions %>
<tr>
<td><%= link_to version.name, :controller => 'versions', :action => 'edit', :id => version %></td>
<td><%=h version.descr %></td>
<td><%=h version.description %></td>
<td>
<%= start_form_tag :controller => 'versions', :action => 'destroy', :id => version %>
<%= submit_tag _('Delete'), :class => "button-small" %>

@ -1,16 +1,21 @@
<h2><%=_('Overview')%></h2>
<div class="splitcontentleft">
<%= @project.descr %>
<%= @project.description %>
<ul>
<li><%=_('Homepage')%>: <%= link_to @project.homepage, @project.homepage %></li>
<li><%=_('Created on')%>: <%= format_date(@project.created_on) %></li>
<% for custom_value in @custom_values %>
<% if !custom_value.value.empty? %>
<li><%= custom_value.custom_field.name%>: <%= custom_value.value%></li>
<% end %>
<% end %>
</ul>
<div class="box">
<h3><%= image_tag "tracker" %> <%=_('Trackers')%></h3>
<ul>
<% for tracker in Tracker.find_all %>
<% for tracker in @trackers %>
<li><%= link_to tracker.name, :controller => 'projects', :action => 'list_issues', :id => @project,
:set_filter => 1,
"tracker_id" => tracker.id %>:
@ -18,8 +23,14 @@
</li>
<% end %>
</ul>
<%= link_to_if_authorized '&#187; ' + _('Report an issue'), :controller => 'projects', :action => 'add_issue', :id => @project %>
<br />
<% if authorize_for 'projects', 'add_issue' %>
&#187; <%=_('Report an issue')%>:
<ul>
<% @trackers.each do |tracker| %>
<li><%= link_to _(tracker.name), :controller => 'projects', :action => 'add_issue', :id => @project, :tracker_id => tracker %></li>
<% end %>
</ul>
<% end %>
<center><small>[ <%= link_to _('View all issues'), :controller => 'projects', :action => 'list_issues', :id => @project, :set_filter => 1 %> ]</small></center>
</div>
</div>
@ -46,7 +57,7 @@
<% for news in @news %>
<p>
<b><%= news.title %></b> <small>(<%= link_to_user news.author %> <%= format_time(news.created_on) %>)</small><br />
<%= news.shortdescr %>
<%= news.summary %>
<small>[<%= link_to _('Read...'), :controller => 'news', :action => 'show', :id => news %>]</small>
</p>
<hr />

@ -1,5 +1,6 @@
<%= error_messages_for 'role' %>
<div class="box">
<!--[form:role]-->
<p><label for="role_name"><%=_('Name')%> <span class="required">*</span></label><br />
<%= text_field 'role', 'name' %></p>
@ -10,7 +11,7 @@
<fieldset><legend><%= _(Permission::GROUPS[group_id]) %></legend>
<% permissions[group_id].each do |p| %>
<div style="width:200px;float:left;"><%= check_box_tag "permission_ids[]", p.id, (@role.permissions.include? p) %>
<%= _(p.descr) %>
<%= _(p.description) %>
</div>
<% end %>
</fieldset>
@ -19,4 +20,4 @@
<a href="javascript:checkAll('role_form', true)"><%=_('Check all')%></a> |
<a href="javascript:checkAll('role_form', false)"><%=_('Uncheck all')%></a><br />
<!--[eoform:role]-->
</div>

@ -1,7 +1,7 @@
<%= error_messages_for 'tracker' %>
<!--[form:tracker]-->
<p><label for="tracker_name"><%=_('Name')%></label><br/>
<p><label for="tracker_name"><%=_('Name')%></label> <span class="required">*</span><br/>
<%= text_field 'tracker', 'name' %></p>
<p><%= check_box 'tracker', 'is_in_chlog' %>

@ -1,31 +1,37 @@
<%= error_messages_for 'user' %>
<div class="box">
<!--[form:user]-->
<p><label for="user_login"><%=_('Login')%></label><br/>
<p><label for="user_login"><%=_('Login')%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'login', :size => 25 %></p>
<p><label for="password"><%=_('Password')%></label><br/>
<p><label for="password"><%=_('Password')%></label> <span class="required">*</span><br/>
<%= password_field_tag 'password', nil, :size => 25 %></p>
<p><label for="password_confirmation"><%=_('Confirmation')%></label><br/>
<p><label for="password_confirmation"><%=_('Confirmation')%></label> <span class="required">*</span><br/>
<%= password_field_tag 'password_confirmation', nil, :size => 25 %></p>
<p><label for="user_firstname"><%=_('Firstname')%></label><br/>
<p><label for="user_firstname"><%=_('Firstname')%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'firstname' %></p>
<p><label for="user_lastname"><%=_('Lastname')%></label><br/>
<p><label for="user_lastname"><%=_('Lastname')%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'lastname' %></p>
<p><label for="user_mail"><%=_('Mail')%></label><br/>
<p><label for="user_mail"><%=_('Mail')%></label> <span class="required">*</span><br/>
<%= text_field 'user', 'mail' %></p>
<p><label for="user_language"><%=_('Language')%></label><br/>
<%= select("user", "language", Localization.langs) %></p>
<%= select("user", "language", Localization.langs.invert) %></p>
<% for custom_value in @custom_values %>
<p><%= custom_field_tag_with_label custom_value %></p>
<% end %>
<div style="clear: both;"></div>
<p><%= check_box 'user', 'admin' %> <label for="user_admin"><%=_('Administrator')%></label></p>
<p><%= check_box 'user', 'mail_notification' %> <label for="user_mail_notification"><%=_('Mail notifications')%></label></p>
<p><%= check_box 'user', 'locked' %> <label for="user_locked"><%=_('Locked')%></label></p>
<!--[eoform:user]-->
</div>

@ -7,7 +7,7 @@
<%= sort_header_tag('lastname', :caption => _('Lastname')) %>
<th><%=_('Mail')%></th>
<%= sort_header_tag('admin', :caption => _('Admin')) %>
<%= sort_header_tag('locked', :caption => _('Locked')) %>
<%= sort_header_tag('status', :caption => _('Status')) %>
<%= sort_header_tag('created_on', :caption => _('Created on')) %>
<%= sort_header_tag('last_login_on', :caption => _('Last login')) %>
<th></th>
@ -25,10 +25,10 @@
<td align="center">
<%= start_form_tag :action => 'edit', :id => user %>
<% if user.locked? %>
<%= hidden_field_tag 'user[locked]', 0 %>
<%= hidden_field_tag 'user[status]', User::STATUS_ACTIVE %>
<%= submit_tag _('Unlock'), :class => "button-small" %>
<% else %>
<%= hidden_field_tag 'user[locked]', 1 %>
<%= hidden_field_tag 'user[status]', User::STATUS_LOCKED %>
<%= submit_tag _('Lock'), :class => "button-small" %>
<% end %>
<%= end_form_tag %>

@ -4,8 +4,8 @@
<p><label for="version_name"><%=_('Version')%></label> <span class="required">*</span><br/>
<%= text_field 'version', 'name', :size => 20 %></p>
<p><label for="version_descr"><%=_('Description')%></label><br/>
<%= text_field 'version', 'descr', :size => 60 %></p>
<p><label for="version_description"><%=_('Description')%></label><br/>
<%= text_field 'version', 'description', :size => 60 %></p>
<p><label for="version_effective_date"><%=_('Date')%></label><br/>
<%= date_select 'version', 'effective_date' %></p>

@ -1,12 +1,13 @@
<div class="splitcontentleft">
<h2><%=_('Welcome')%> !</h2>
<h2><%= $RDM_WELCOME_TITLE || _('Welcome') %> !</h2>
<p><%= $RDM_WELCOME_TEXT %></p>
<div class="box">
<h3><%=_('Latest news')%></h3>
<% for news in @news %>
<p>
<b><%= news.title %></b> (<%= link_to_user news.author %> <%= format_time(news.created_on) %> - <%= news.project.name %>)<br />
<%= news.shortdescr %><br />
<%= news.summary %><br />
[<%= link_to 'Read...', :controller => 'news', :action => 'show', :id => news %>]
</p>
<hr />
@ -21,7 +22,7 @@
<% for project in @projects %>
<li>
<%= link_to project.name, :controller => 'projects', :action => 'show', :id => project %> (added <%= format_time(project.created_on) %>)<br />
<%= project.descr %>
<%= project.description %>
</li>
<% end %>
</ul>

@ -0,0 +1,57 @@
# redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
# To set your own configuration, rename this file to config_custom.rb
# and edit parameters below
# Don't forget to restart the application after any change.
# Application host name
# Used to provide absolute links in mail notifications
# $RDM_HOST_NAME = "somenet.foo"
# File storage path
# Directory used to store uploaded files
# #{RAILS_ROOT} represents application's home directory
# $RDM_STORAGE_PATH = "#{RAILS_ROOT}/files"
# Set $RDM_LOGIN_REQUIRED to true if you want to force users to login
# to access any page of the application
# $RDM_LOGIN_REQUIRED = false
# Uncomment to disable user self-registration
# $RDM_SELF_REGISTRATION = false
# Default langage ('en', 'es', 'fr' are available)
# $RDM_DEFAULT_LANG = 'en'
# Page title
# $RDM_HEADER_TITLE = "Title"
# Page sub-title
# $RDM_HEADER_SUBTITLE = "Sub title"
# Welcome page title
# $RDM_WELCOME_TITLE = "Welcome"
# Welcome page text
# $RDM_WELCOME_TEXT = ""
# Signature displayed in footer
# Email adresses will be automatically displayed as a mailto link
# $RDM_FOOTER_SIG = "admin@somenet.foo"

@ -68,18 +68,67 @@ end
# inflect.uncountable %w( fish sheep )
# end
# Include your application configuration below
# application name
RDM_APP_NAME = "redMine"
# application version
RDM_APP_VERSION = "0.2.0"
if File.exist? File.join(File.dirname(__FILE__), 'config_custom.rb')
begin
print "=> Loading config_custom.rb... "
require File.join(File.dirname(__FILE__), 'config_custom')
puts "done."
rescue Exception => detail
puts
puts detail
puts detail.backtrace.join("\n")
puts "=> Error in config_custom.rb. Check your configuration."
exit
end
end
# IMPORTANT !!! DO NOT MODIFY PARAMETERS HERE
# Instead, rename config_custom.example.rb to config_custom.rb
# and set your own configuration in that file
# Parameters defined in config_custom.rb override those defined below
# application host name
RDM_HOST_NAME = "somenet.foo"
$RDM_HOST_NAME ||= "localhost:3000"
# file storage path
RDM_STORAGE_PATH = "#{RAILS_ROOT}/files"
$RDM_STORAGE_PATH ||= "#{RAILS_ROOT}/files"
# if RDM_LOGIN_REQUIRED is set to true, login is required to access the application
RDM_LOGIN_REQUIRED = false
$RDM_LOGIN_REQUIRED ||= false
# default langage
RDM_DEFAULT_LANG = 'en'
$RDM_DEFAULT_LANG ||= 'en'
# page title
$RDM_HEADER_TITLE ||= "redMine"
# page sub-title
$RDM_HEADER_SUBTITLE ||= "Project management"
# footer signature
$RDM_FOOTER_SIG = "admin@somenet.foo"
# application name
RDM_APP_NAME = "redMine"
# application version
RDM_APP_VERSION = "0.3.0"
ActiveRecord::Errors.default_error_messages = {
:inclusion => "activerecord_error_inclusion",
:exclusion => "activerecord_error_exclusion",
:invalid => "activerecord_error_invalid",
:confirmation => "activerecord_error_confirmation",
:accepted => "activerecord_error_accepted",
:empty => "activerecord_error_empty",
:blank => "activerecord_error_blank",
:too_long => "activerecord_error_too_long",
:too_short => "activerecord_error_too_short",
:wrong_length => "activerecord_error_wrong_length",
:taken => "activerecord_error_taken",
:not_a_number => "activerecord_error_not_a_number"
}
ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "<span class=\"fieldWithErrors\">#{html_tag}</span>" }
GLoc.set_config :default_language => $RDM_DEFAULT_LANG
GLoc.clear_strings
GLoc.set_kcode
GLoc.load_localized_strings
GLoc.set_config(:raise_string_not_found_errors => false)

@ -13,3 +13,4 @@ config.whiny_nils = true
config.action_controller.consider_all_requests_local = true
config.action_controller.perform_caching = false
config.action_mailer.delivery_method = :test

@ -5,6 +5,34 @@ Copyright (C) 2006 Jean-Philippe Lang
http://redmine.org/
== xx/xx/2006 v0.3.0
* user authentication against multiple LDAP
* token based "lost password" functionality
* user self-registration functionality (optional)
* custom fields now available for issues, users and projects
* new custom field format "text" (textarea)
* project & administration drop down menus in navigation bar
* error messages internationalization
* Localization plugin replaced with GLoc 1.1.0
* new filter in issues list: "Fixed version"
* colored background for active filters on issues list
* custom configuration is now defined in config/config_custom.rb
* user object no more stored in session (only user_id)
* news summary field is no longer required
* Fixed: boolean custom field not working
* Fixed: error messages for custom fields are not displayed
* Fixed: custom fields values are not validated on issue update
* Fixed: user unable to choose an empty value for 'List' custom fields
* Fixed: no issue categories sorting
* Fixed: incorrect versions sorting
== 07/12/2006 - v0.2.2
* Fixed: bug in "issues list"
== 07/09/2006 - v0.2.1
* new databases supported: Oracle, PostgreSQL, SQL Server

@ -49,21 +49,11 @@ Supported databases:
== Configuration
You can setup a few things in config/environment.rb:
A sample configuration file is provided: "config/config_custom.example.rb"
Rename it to config_custom.rb and edit parameters.
Don't forget to restart the application after any change.
config.action_mailer.server_settings: SMTP server configuration
config.action_mailer.perform_deliveries: set to false to disable mail delivering
RDM_HOST_NAME: hostname used to provide urls in notification mails
RDM_STORAGE_PATH: path for all attachments storage (default: "#{RAILS_ROOT}/files")
"#{RAILS_ROOT}/" represents application main directory
RDM_LOGIN_REQUIRED: set to true if you want to force users to login to access
any part of the application (default: false)
RDM_DEFAULT_LANG: default language for anonymous users: 'en' (default), 'es', 'fr' available

@ -0,0 +1,113 @@
_gloc_rule_default: '|n| n==1 ? "" : "_plural" '
actionview_datehelper_select_day_prefix:
actionview_datehelper_select_month_names: January,February,March,April,May,June,July,August,September,October,November,December
actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec
actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 day
actionview_datehelper_time_in_words_day_plural: %d days
actionview_datehelper_time_in_words_hour_about: about an hour
actionview_datehelper_time_in_words_hour_about_plural: about %d hours
actionview_datehelper_time_in_words_hour_about_single: about an hour
actionview_datehelper_time_in_words_minute: 1 minute
actionview_datehelper_time_in_words_minute_half: half a minute
actionview_datehelper_time_in_words_minute_less_than: less than a minute
actionview_datehelper_time_in_words_minute_plural: %d minutes
actionview_datehelper_time_in_words_minute_single: 1 minute
actionview_datehelper_time_in_words_second_less_than: less than a second
actionview_datehelper_time_in_words_second_less_than_plural: less than %d seconds
actionview_instancetag_blank_option: Please select
activerecord_error_inclusion: is not included in the list
activerecord_error_exclusion: is reserved
activerecord_error_invalid: is invalid
activerecord_error_confirmation: doesn't match confirmation
activerecord_error_accepted: must be accepted
activerecord_error_empty: can't be empty
activerecord_error_blank: can't be blank
activerecord_error_too_long: is too long
activerecord_error_too_short: is too short
activerecord_error_wrong_length: is the wrong length
activerecord_error_taken: has already been taken
activerecord_error_not_a_number: is not a number
general_fmt_age: %d yr
general_fmt_age_plural: %d yrs
general_fmt_date: %%b %%d, %%Y (%%a)
general_fmt_datetime: %%b %%d, %%Y (%%a), %%I:%%M %%p
general_fmt_datetime_short: %%b %%d, %%I:%%M %%p
general_fmt_time: %%I:%%M %%p
general_text_No: 'No'
general_text_Yes: 'Yes'
general_text_no: 'no'
general_text_yes: 'yes'
notice_account_updated: Account was successfully updated.
notice_account_invalid_creditentials: Invalid user or password
notice_account_password_updated: Password was successfully updated.
notice_account_wrong_password: Wrong password
notice_account_register_done: Account was successfully created.
notice_account_unknown_email: Unknown user.
notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you.
gui_menu_home: Home
gui_menu_my_page: My page
gui_menu_projects: Projects
gui_menu_my_account: My account
gui_menu_admin: Administration
gui_menu_login: Login
gui_menu_logout: Logout
gui_menu_help: Help
gui_validation_error: 1 error
gui_validation_error_plural: %d errors
field_name: Name
field_description: Description
field_summary: Summary
field_is_required: Required
field_firstname: Firstname
field_lastname: Lastname
field_mail: Email
field_filename: File
field_filesize: Size
field_downloads: Downloads
field_author: Author
field_created_on: Created
field_updated_on: Updated
field_field_format: Format
field_is_for_all: For all projects
field_possible_values: Possible values
field_regexp: Regular expression
field_min_length: Minimum length
field_max_length: Maximum length
field_value: Value
field_category: Catogory
field_title: Title
field_project: Project
field_issue: Issue
field_status: Status
field_notes: Notes
field_is_closed: Issue closed
field_is_default: Default status
field_html_color: Color
field_tracker: Tracker
field_subject: Subject
field_assigned_to: Assigned to
field_priority: Priority
field_fixed_version: Fixed version
field_user: User
field_role: Role
field_homepage: Homepage
field_is_public: Public
field_parent: Subproject de
field_is_in_chlog: Issues displayed in changelog
field_login: Login
field_mail_notification: Mail notifications
field_admin: Administrator
field_locked: Locked
field_last_login_on: Last connection
field_language: Language
field_effective_date: Date
field_password: Password
field_password_confirmation: Confirmation

@ -1,4 +1,6 @@
Localization.define('en', 'English') do |l|
l.store '(date)', lambda { |t| t.strftime('%m/%d/%Y') }
l.store '(time)', lambda { |t| t.strftime('%m/%d/%Y %I:%M%p') }
l.store '%d errors', ['1 error', '%d errors']
end

@ -0,0 +1,199 @@
_gloc_rule_default: '|n| n==1 ? "" : "_plural" '
actionview_datehelper_select_day_prefix:
actionview_datehelper_select_month_names: Janvier,Février,Mars,Avril,Mai,Juin,Juillet,Août,Septembre,Octobre,Novembre,Décembre
actionview_datehelper_select_month_names_abbr: Jan,Fév,Mars,Avril,Mai,Juin,Juil,Août,Sept,Oct,Nov,Déc
actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 jour
actionview_datehelper_time_in_words_day_plural: %d jours
actionview_datehelper_time_in_words_hour_about: about an hour
actionview_datehelper_time_in_words_hour_about_plural: about %d hours
actionview_datehelper_time_in_words_hour_about_single: about an hour
actionview_datehelper_time_in_words_minute: 1 minute
actionview_datehelper_time_in_words_minute_half: 30 secondes
actionview_datehelper_time_in_words_minute_less_than: moins d'une minute
actionview_datehelper_time_in_words_minute_plural: %d minutes
actionview_datehelper_time_in_words_minute_single: 1 minute
actionview_datehelper_time_in_words_second_less_than: moins d'une seconde
actionview_datehelper_time_in_words_second_less_than_plural: moins de %d secondes
actionview_instancetag_blank_option: Choisir
activerecord_error_inclusion: n'est pas inclus dans la liste
activerecord_error_exclusion: est reservé
activerecord_error_invalid: est invalide
activerecord_error_confirmation: ne correspond pas à la confirmation
activerecord_error_accepted: doit être accepté
activerecord_error_empty: doit être renseigné
activerecord_error_blank: doit être renseigné
activerecord_error_too_long: est trop long
activerecord_error_too_short: est trop court
activerecord_error_wrong_length: n'est pas de la bonne longueur
activerecord_error_taken: est déjà utilisé
activerecord_error_not_a_number: n'est pas un nombre
general_fmt_age: %d an
general_fmt_age_plural: %d ans
general_fmt_date: %%d/%%m/%%Y
general_fmt_datetime: %%d/%%m/%%Y %%H:%%M
general_fmt_datetime_short: %%d/%%m %%H:%%M
general_fmt_time: %%H:%%M
general_text_No: 'Non'
general_text_Yes: 'Oui'
general_text_no: 'non'
general_text_yes: 'oui'
notice_account_updated: Le compte a été mis à jour avec succès.
notice_account_invalid_creditentials: Identifiant ou mot de passe invalide.
notice_account_password_updated: Mot de passe mis à jour avec succès.
notice_account_wrong_password: Mot de passe incorrect
notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a été envoyé.
notice_account_unknown_email: Aucun compte ne correspond à cette adresse.
notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a été envoyé.
notice_account_activated: Votre compte a été activé. Vous pouvez à présent vous connecter.
notice_successful_update: Mise à jour effectuée avec succès.
notice_successful_create: Création effectuée avec succès.
notice_successful_delete: Suppression effectuée avec succès.
notice_successful_connection: Connection réussie.
gui_validation_error: 1 erreur
gui_validation_error_plural: %d erreurs
field_name: Nom
field_description: Description
field_summary: Résumé
field_is_required: Obligatoire
field_firstname: Prénom
field_lastname: Nom
field_mail: Email
field_filename: Fichier
field_filesize: Taille
field_downloads: Téléchargements
field_author: Auteur
field_created_on: Créé
field_updated_on: Mis à jour
field_field_format: Format
field_is_for_all: Pour tous les projets
field_possible_values: Valeurs possibles
field_regexp: Expression régulière
field_min_length: Longueur minimum
field_max_length: Longueur maximum
field_value: Valeur
field_category: Catégorie
field_title: Titre
field_project: Projet
field_issue: Demande
field_status: Statut
field_notes: Notes
field_is_closed: Demande fermée
field_is_default: Statut par défaut
field_html_color: Couleur
field_tracker: Tracker
field_subject: Sujet
field_assigned_to: Assigné à
field_priority: Priorité
field_fixed_version: Version corrigée
field_user: Utilisateur
field_role: Rôle
field_homepage: Site web
field_is_public: Public
field_parent: Sous-projet de
field_is_in_chlog: Demandes affichées dans l'historique
field_login: Identifiant
field_mail_notification: Notifications par mail
field_admin: Administrateur
field_locked: Verrouillé
field_last_login_on: Dernière connexion
field_language: Langue
field_effective_date: Date
field_password: Mot de passe
field_new_password: Nouveau mot de passe
field_password_confirmation: Confirmation
field_version: Version
field_type: Type
field_host: Hôte
field_port: Port
field_account: Compte
field_base_dn: Base DN
field_attr_login: Attribut Identifiant
field_attr_firstname: Attribut Prénom
field_attr_lastname: Attribut Nom
field_attr_mail: Attribut Email
field_onthefly: Création des utilisateurs à la volée
label_user: Utilisateur
label_user_plural: Utilisateurs
label_user_new: Nouvel utilisateur
label_project: Projet
label_project_new: Nouveau projet
label_project_plural: Projets
label_issue: Demande
label_issue_new: Nouvelle demande
label_issue_plural: Demandes
label_role: Rôle
label_role_plural: Rôles
label_role_add: Nouveau rôle
label_role_and_permissions: Rôles et permissions
label_tracker: Tracker
label_tracker_plural: Trackers
label_tracker_add: Nouveau tracker
label_workflow: Workflow
label_issue_status: Statut de demandes
label_issue_status_plural: Statuts de demandes
label_issue_status_add: Nouveau statut
label_custom_field: Champ personnalisé
label_custom_field_plural: Champs personnalisés
label_custom_field_new: Nouveau champ personnalisé
label_enumerations: Listes de valeurs
label_information: Information
label_information_plural: Informations
label_please_login: Identification
label_register: S'enregistrer
label_password_lost: Mot de passe perdu
label_home: Accueil
label_my_page: Ma page
label_my_account: Mon compte
label_administration: Administration
label_login: Connexion
label_logout: Déconnexion
label_help: Aide
label_reported_issues: Demandes soumises
label_assigned_to_me_issues: Demandes qui me sont assignées
label_last_login: Dernière connexion
label_last_updates: Dernière mise à jour
label_last_updates_plural: %d dernières mises à jour
label_registered_on: Inscrit le
label_activity: Activité
label_new: Nouveau
label_logged_as: Connecté en tant que
label_environment: Environnement
label_authentication: Authentification
label_auth_source: Mode d'authentification
label_auth_source_new: Nouveau mode d'authentification
label_auth_source_plural: Modes d'authentification
label_subproject: Sous-projet
label_subproject_plural: Sous-projets
label_min_max_length: Longueurs mini - maxi
label_list: Liste
label_date: Date
label_integer: Entier
label_boolean: Booléen
label_string: Chaîne
label_text: Texte
label_attribute: Attribut
label_attribute_plural: Attributs
button_login: Connexion
button_submit: Soumettre
button_save: Valider
button_check_all: Tout cocher
button_uncheck_all: Tout décocher
button_delete: Supprimer
button_create: Créer
button_test: Tester
text_select_mail_notifications: Sélectionner les actions pour lesquelles la notification par mail doit être activée.
text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 pour aucune restriction
text_possible_values_info: valeurs séparées par |

@ -27,12 +27,36 @@ Localization.define('fr', 'Français') do |l|
l.store 'Document categories', 'Catégories de documents'
l.store 'Uncategorized', 'Sans catégorie'
l.store 'User documentation', 'Documentation utilisateur'
l.store 'Technical documentation', 'Documentation technique'
l.store 'Technical documentation', 'Documentation technique'
# custom fields formats
l.store 'String', 'Chaîne'
l.store 'Integer', 'Entier'
l.store 'Date', 'Date'
l.store 'Boolean', 'Booléen'
l.store 'List', 'Liste'
# dates
l.store '(date)', lambda { |t| t.strftime('%d/%m/%Y') }
l.store '(time)', lambda { |t| t.strftime('%d/%m/%Y %H:%M') }
# ./script/../config/../app/views/account/login.rhtml
# error messages
l.store '%d errors', ['1 erreur', '%d erreurs']
l.store "is not included in the list", "n'est pas inclus dans la liste"
l.store "is reserved", "est réservé"
l.store "is invalid", "n'est pas valide"
l.store "doesn't match confirmation", "ne correspond pas à la confirmation"
l.store "must be accepted", "doit être accepté"
l.store "can't be empty", "ne doit pas être vide"
l.store "can't be blank", "doit être renseigné"
l.store "is too long", "est trop long"
l.store "is too short", "est trop court"
l.store "is the wrong length", "n'est pas de la bonne longueur"
l.store "has already been taken", "est déjà utilisé"
l.store "is not a number", "doit être un nombre"
# notice messages
l.store 'Invalid user/password', 'Identifiant/Mot de passe invalide'
# ./script/../config/../app/views/account/my_account.rhtml
l.store 'My account', 'Mon compte'
@ -59,6 +83,9 @@ Localization.define('fr', 'Français') do |l|
# ./script/../config/../app/views/account/login.rhtml
l.store 'Please login', 'Identification'
l.store 'Register', "S'enregistrer"
l.store 'Password lost', 'Mot de passe perdu'
l.store 'Submit', 'Soumettre'
# ./script/../config/../app/views/account/show.rhtml
l.store 'Registered on', 'Inscrit le'
@ -97,6 +124,7 @@ Localization.define('fr', 'Français') do |l|
# ./script/../config/../app/views/custom_fields/list.rhtml
l.store 'Name', 'Nom'
l.store 'For', 'Pour'
l.store 'Type', 'Type'
l.store 'Required', 'Obligatoire'
l.store 'For all projects', 'Pour tous les projets'

@ -0,0 +1,24 @@
desc 'Create YAML test fixtures from data in an existing database.
Defaults to development database. Set RAILS_ENV to override.'
task :extract_fixtures => :environment do
sql = "SELECT * FROM %s"
skip_tables = ["schema_info"]
ActiveRecord::Base.establish_connection
(ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|
i = "000"
File.open("#{RAILS_ROOT}/#{table_name}.yml", 'w' ) do |file|
data = ActiveRecord::Base.connection.select_all(sql % table_name)
file.write data.inject({}) { |hash, record|
# cast extracted values
ActiveRecord::Base.connection.columns(table_name).each { |col|
record[col.name] = col.type_cast(record[col.name]) if record[col.name]
}
hash["#{table_name}_#{i.succ!}"] = record
hash
}.to_yaml
end
end
end

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 483 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

@ -0,0 +1,556 @@
//*****************************************************************************
// Do not remove this notice.
//
// Copyright 2000-2004 by Mike Hall.
// See http://www.brainjar.com for terms of use.
//*****************************************************************************
//----------------------------------------------------------------------------
// Emulation de la fonction push pour IE5.0
//----------------------------------------------------------------------------
if(!Array.prototype.push){Array.prototype.push=function(){for(var i=0;i<arguments.length;i++)this[this.length]=arguments[i];};};
//----------------------------------------------------------------------------
// Code to determine the browser and version.
//----------------------------------------------------------------------------
function Browser() {
var ua, s, i;
this.isIE = false; // Internet Explorer
this.isOP = false; // Opera
this.isNS = false; // Netscape
this.version = null;
//-- debut ajout ci ----
this.isIE5mac = false; // Internet Explorer 5 mac
//-- fin ajout ci ----
ua = navigator.userAgent;
//-- debut ajout ci ----
if (ua.indexOf("Opera")==-1 && ua.indexOf("MSIE 5")>-1 && ua.indexOf("Mac")>-1) {
this.isIE5mac = true;
this.version = "";
return;
}
//-- fin ajout ci ----
s = "Opera";
if ((i = ua.indexOf(s)) >= 0) {
this.isOP = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
}
s = "Netscape6/";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
}
// Treat any other "Gecko" browser as Netscape 6.1.
s = "Gecko";
if ((i = ua.indexOf(s)) >= 0) {
this.isNS = true;
this.version = 6.1;
return;
}
s = "MSIE";
if ((i = ua.indexOf(s))) {
this.isIE = true;
this.version = parseFloat(ua.substr(i + s.length));
return;
}
}
var browser = new Browser();
//----------------------------------------------------------------------------
// Code for handling the menu bar and active button.
//----------------------------------------------------------------------------
var activeButton = null;
function buttonClick(event, menuId) {
var button;
// Get the target button element.
if (browser.isIE)
button = window.event.srcElement;
else
button = event.currentTarget;
// Blur focus from the link to remove that annoying outline.
button.blur();
// Associate the named menu to this button if not already done.
// Additionally, initialize menu display.
if (button.menu == null) {
button.menu = document.getElementById(menuId);
if (button.menu.isInitialized == null)
menuInit(button.menu);
}
// Set mouseout event handler for the button, if not already done.
if (button.onmouseout == null)
button.onmouseout = buttonOrMenuMouseout;
// Exit if this button is the currently active one.
if (button == activeButton)
return false;
// Reset the currently active button, if any.
if (activeButton != null)
resetButton(activeButton);
// Activate this button, unless it was the currently active one.
if (button != activeButton) {
depressButton(button);
activeButton = button;
}
else
activeButton = null;
return false;
}
function buttonMouseover(event, menuId) {
var button;
//-- debut ajout ci ----
if (!browser.isIE5mac) {
//-- fin ajout ci ----
//-- debut ajout ci ----
cicacheselect();
//-- fin ajout ci ----
// Activates this button's menu if no other is currently active.
if (activeButton == null) {
buttonClick(event, menuId);
return;
}
// Find the target button element.
if (browser.isIE)
button = window.event.srcElement;
else
button = event.currentTarget;
// If any other button menu is active, make this one active instead.
if (activeButton != null && activeButton != button)
buttonClick(event, menuId);
//-- debut ajout ci ----
}
//-- fin ajout ci ----
}
function depressButton(button) {
var x, y;
// Update the button's style class to make it look like it's
// depressed.
button.className += " menuButtonActive";
// Set mouseout event handler for the button, if not already done.
if (button.onmouseout == null)
button.onmouseout = buttonOrMenuMouseout;
if (button.menu.onmouseout == null)
button.menu.onmouseout = buttonOrMenuMouseout;
// Position the associated drop down menu under the button and
// show it.
x = getPageOffsetLeft(button);
y = getPageOffsetTop(button) + button.offsetHeight - 1;
// For IE, adjust position.
if (browser.isIE) {
x += button.offsetParent.clientLeft;
y += button.offsetParent.clientTop;
}
button.menu.style.left = x + "px";
button.menu.style.top = y + "px";0
button.menu.style.visibility = "visible";
}
function resetButton(button) {
// Restore the button's style class.
removeClassName(button, "menuButtonActive");
// Hide the button's menu, first closing any sub menus.
if (button.menu != null) {
closeSubMenu(button.menu);
button.menu.style.visibility = "hidden";
}
}
//----------------------------------------------------------------------------
// Code to handle the menus and sub menus.
//----------------------------------------------------------------------------
function menuMouseover(event) {
var menu;
//-- debut ajout ci ----
if (!browser.isIE5mac) {
//-- fin ajout ci ----
//-- debut ajout ci ----
cicacheselect();
//-- fin ajout ci ----
// Find the target menu element.
if (browser.isIE)
menu = getContainerWith(window.event.srcElement, "DIV", "menu");
else
menu = event.currentTarget;
// Close any active sub menu.
if (menu.activeItem != null)
closeSubMenu(menu);
//-- debut ajout ci ----
}
//-- fin ajout ci ----
}
function menuItemMouseover(event, menuId) {
var item, menu, x, y;
//-- debut ajout ci ----
cicacheselect();
//-- fin ajout ci ----
// Find the target item element and its parent menu element.
if (browser.isIE)
item = getContainerWith(window.event.srcElement, "A", "menuItem");
else
item = event.currentTarget;
menu = getContainerWith(item, "DIV", "menu");
// Close any active sub menu and mark this one as active.
if (menu.activeItem != null)
closeSubMenu(menu);
menu.activeItem = item;
// Highlight the item element.
item.className += " menuItemHighlight";
// Initialize the sub menu, if not already done.
if (item.subMenu == null) {
item.subMenu = document.getElementById(menuId);
if (item.subMenu.isInitialized == null)
menuInit(item.subMenu);
}
// Set mouseout event handler for the sub menu, if not already done.
if (item.subMenu.onmouseout == null)
item.subMenu.onmouseout = buttonOrMenuMouseout;
// Get position for submenu based on the menu item.
x = getPageOffsetLeft(item) + item.offsetWidth;
y = getPageOffsetTop(item);
// Adjust position to fit in view.
var maxX, maxY;
if (browser.isIE) {
maxX = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft) +
(document.documentElement.clientWidth != 0 ? document.documentElement.clientWidth : document.body.clientWidth);
maxY = Math.max(document.documentElement.scrollTop, document.body.scrollTop) +
(document.documentElement.clientHeight != 0 ? document.documentElement.clientHeight : document.body.clientHeight);
}
if (browser.isOP) {
maxX = document.documentElement.scrollLeft + window.innerWidth;
maxY = document.documentElement.scrollTop + window.innerHeight;
}
if (browser.isNS) {
maxX = window.scrollX + window.innerWidth;
maxY = window.scrollY + window.innerHeight;
}
maxX -= item.subMenu.offsetWidth;
maxY -= item.subMenu.offsetHeight;
if (x > maxX)
x = Math.max(0, x - item.offsetWidth - item.subMenu.offsetWidth
+ (menu.offsetWidth - item.offsetWidth));
y = Math.max(0, Math.min(y, maxY));
// Position and show the sub menu.
item.subMenu.style.left = x + "px";
item.subMenu.style.top = y + "px";
item.subMenu.style.visibility = "visible";
// Stop the event from bubbling.
if (browser.isIE)
window.event.cancelBubble = true;
else
event.stopPropagation();
}
function closeSubMenu(menu) {
if (menu == null || menu.activeItem == null)
return;
// Recursively close any sub menus.
if (menu.activeItem.subMenu != null) {
closeSubMenu(menu.activeItem.subMenu);
menu.activeItem.subMenu.style.visibility = "hidden";
menu.activeItem.subMenu = null;
}
removeClassName(menu.activeItem, "menuItemHighlight");
menu.activeItem = null;
}
function buttonOrMenuMouseout(event) {
var el;
// If there is no active button, exit.
if (activeButton == null)
return;
// Find the element the mouse is moving to.
if (browser.isIE)
el = window.event.toElement;
else if (event.relatedTarget != null)
el = (event.relatedTarget.tagName ? event.relatedTarget : event.relatedTarget.parentNode);
// If the element is not part of a menu, reset the active button.
if (getContainerWith(el, "DIV", "menu") == null) {
resetButton(activeButton);
activeButton = null;
//-- debut ajout ci ----
cimontreselect();
//-- fin ajout ci ----
}
}
//----------------------------------------------------------------------------
// Code to initialize menus.
//----------------------------------------------------------------------------
function menuInit(menu) {
var itemList, spanList;
var textEl, arrowEl;
var itemWidth;
var w, dw;
var i, j;
// For IE, replace arrow characters.
if (browser.isIE) {
menu.style.lineHeight = "2.5ex";
spanList = menu.getElementsByTagName("SPAN");
for (i = 0; i < spanList.length; i++)
if (hasClassName(spanList[i], "menuItemArrow")) {
spanList[i].style.fontFamily = "Webdings";
spanList[i].firstChild.nodeValue = "4";
}
}
// Find the width of a menu item.
itemList = menu.getElementsByTagName("A");
if (itemList.length > 0)
itemWidth = itemList[0].offsetWidth;
else
return;
// For items with arrows, add padding to item text to make the
// arrows flush right.
for (i = 0; i < itemList.length; i++) {
spanList = itemList[i].getElementsByTagName("SPAN");
textEl = null;
arrowEl = null;
for (j = 0; j < spanList.length; j++) {
if (hasClassName(spanList[j], "menuItemText"))
textEl = spanList[j];
if (hasClassName(spanList[j], "menuItemArrow"))
arrowEl = spanList[j];
}
if (textEl != null && arrowEl != null) {
textEl.style.paddingRight = (itemWidth
- (textEl.offsetWidth + arrowEl.offsetWidth)) + "px";
// For Opera, remove the negative right margin to fix a display bug.
if (browser.isOP)
arrowEl.style.marginRight = "0px";
}
}
// Fix IE hover problem by setting an explicit width on first item of
// the menu.
if (browser.isIE) {
w = itemList[0].offsetWidth;
itemList[0].style.width = w + "px";
dw = itemList[0].offsetWidth - w;
w -= dw;
itemList[0].style.width = w + "px";
}
// Mark menu as initialized.
menu.isInitialized = true;
}
//----------------------------------------------------------------------------
// General utility functions.
//----------------------------------------------------------------------------
function getContainerWith(node, tagName, className) {
// Starting with the given node, find the nearest containing element
// with the specified tag name and style class.
while (node != null) {
if (node.tagName != null && node.tagName == tagName &&
hasClassName(node, className))
return node;
node = node.parentNode;
}
return node;
}
function hasClassName(el, name) {
var i, list;
// Return true if the given element currently has the given class
// name.
list = el.className.split(" ");
for (i = 0; i < list.length; i++)
if (list[i] == name)
return true;
return false;
}
function removeClassName(el, name) {
var i, curList, newList;
if (el.className == null)
return;
// Remove the given class name from the element's className property.
newList = new Array();
curList = el.className.split(" ");
for (i = 0; i < curList.length; i++)
if (curList[i] != name)
newList.push(curList[i]);
el.className = newList.join(" ");
}
function getPageOffsetLeft(el) {
var x;
// Return the x coordinate of an element relative to the page.
x = el.offsetLeft;
if (el.offsetParent != null)
x += getPageOffsetLeft(el.offsetParent);
return x;
}
function getPageOffsetTop(el) {
var y;
// Return the x coordinate of an element relative to the page.
y = el.offsetTop;
if (el.offsetParent != null)
y += getPageOffsetTop(el.offsetParent);
return y;
}
//-- debut ajout ci ----
function cicacheselect(){
if (browser.isIE) {
oSelects = document.getElementsByTagName('SELECT');
if (oSelects.length > 0) {
for (i = 0; i < oSelects.length; i++) {
oSlt = oSelects[i];
if (oSlt.style.visibility != 'hidden') {oSlt.style.visibility = 'hidden';}
}
}
oSelects = document.getElementsByName('masquable');
if (oSelects.length > 0) {
for (i = 0; i < oSelects.length; i++) {
oSlt = oSelects[i];
if (oSlt.style.visibility != 'hidden') {oSlt.style.visibility = 'hidden';}
}
}
}
}
function cimontreselect(){
if (browser.isIE) {
oSelects = document.getElementsByTagName('SELECT');
if (oSelects.length > 0) {
for (i = 0; i < oSelects.length; i++) {
oSlt = oSelects[i];
if (oSlt.style.visibility != 'visible') {oSlt.style.visibility = 'visible';}
}
}
oSelects = document.getElementsByName('masquable');
if (oSelects.length > 0) {
for (i = 0; i < oSelects.length; i++) {
oSlt = oSelects[i];
if (oSlt.style.visibility != 'visible') {oSlt.style.visibility = 'visible';}
}
}
}
}
//-- fin ajout ci ----

@ -15,6 +15,7 @@ color:#303030;
background:#e8eaec;
}
a{
color:#467aa7;
font-weight:bold;
@ -136,7 +137,6 @@ padding:20px 10px 10px 20px;
/*position: absolute;*/
margin: 0 0 0 140px;
border-left: 1px dashed #c0c0c0;
}
#content h2{
@ -180,6 +180,11 @@ form {
width:100%;
}
textarea {
padding:0;
margin:0;
}
input {
vertical-align: top;
}
@ -191,7 +196,15 @@ input.button-small
select.select-small
{
font-size: 0.8em;
border: 1px solid #7F9DB9;
padding: 1px;
font-size: 0.8em;
}
.active-filter
{
background-color: #F9FA9E;
}
label {
@ -201,6 +214,12 @@ label {
fieldset {
border:1px solid #7F9DB9;
padding: 6px;
}
legend {
color: #505050;
}
.required {
@ -328,4 +347,8 @@ color:#505050;
line-height:1.5em;
}
.login {
width: 50%;
text-align: left;
}

@ -0,0 +1,39 @@
/*========== Drop down menu ==============*/
div.menu {
background-color: #FFFFFF;
border-style: solid;
border-width: 1px;
border-color: #7F9DB9;
position: absolute;
top: 0px;
left: 0px;
padding: 0;
visibility: hidden;
z-index: 101;
}
div.menu a.menuItem {
font-size: 10px;
font-weight: normal;
line-height: 2em;
color: #000000;
background-color: #FFFFFF;
cursor: default;
display: block;
padding: 0 1em;
margin: 0;
border: 0;
text-decoration: none;
white-space: nowrap;
}
div.menu a.menuItem:hover, div.menu a.menuItemHighlight {
background-color: #80b0da;
color: #ffffff;
}
div.menu a.menuItem span.menuItemText {}
div.menu a.menuItem span.menuItemArrow {
margin-right: -.75em;
}

@ -1,27 +1,27 @@
.fieldWithErrors {
padding: 2px;
margin: 0px;
background-color: red;
display: table;
}
#errorExplanation {
width: 400px;
border: 2px solid red;
border: 0;
padding: 7px;
padding-bottom: 12px;
margin-bottom: 20px;
background-color: #f0f0f0;
padding-bottom: 3px;
margin-bottom: 0px;
/*background-color: #f0f0f0;*/
}
#errorExplanation h2 {
text-align: left;
font-weight: bold;
padding: 5px 5px 5px 15px;
font-size: 12px;
padding: 5px 5px 10px 26px;
font-size: 1em;
margin: -7px;
background-color: #c00;
color: #fff;
background: url(../images/alert.png) no-repeat 6px 6px;
}
#errorExplanation p {
@ -31,8 +31,9 @@
}
#errorExplanation ul li {
font-size: 12px;
list-style: square;
font-size: 1em;
list-style: none;
margin-left: -16px;
}
div.uploadStatus {

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

Loading…
Cancel
Save