Compare commits

..
1 Commits
Author SHA1 Message Date
Jean-Philippe Lang 66866954f6 tagged version 0.4.2
git-svn-id: http://redmine.rubyforge.org/svn/tags/0.4.2@260 e93f8b46-1217-0410-a6f0-8f06a7374b81
2007-02-18 19:59:19 +00:00
363 changed files with 9851 additions and 19947 deletions

No files matched your search

-25
View File
@@ -1,25 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 SysApi < ActionWebService::API::Base
api_method :projects,
:expects => [],
:returns => [[Project]]
api_method :repository_created,
:expects => [:int, :string],
:returns => [:int]
end
+130 -130
View File
@@ -1,131 +1,131 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class AccountController < ApplicationController class AccountController < ApplicationController
layout 'base' layout 'base'
helper :custom_fields helper :custom_fields
include CustomFieldsHelper include CustomFieldsHelper
# prevents login action to be filtered by check_if_login_required application scope filter # prevents login action to be filtered by check_if_login_required application scope filter
skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register] skip_before_filter :check_if_login_required, :only => [:login, :lost_password, :register]
before_filter :require_login, :only => :logout before_filter :require_login, :only => :logout
# Show user's account # Show user's account
def show def show
@user = User.find(params[:id]) @user = User.find(params[:id])
@custom_values = @user.custom_values.find(:all, :include => :custom_field) @custom_values = @user.custom_values.find(:all, :include => :custom_field)
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
# Login request and validation # Login request and validation
def login def login
if request.get? if request.get?
# Logout user # Logout user
self.logged_in_user = nil self.logged_in_user = nil
else else
# Authenticate user # Authenticate user
user = User.try_to_login(params[:login], params[:password]) user = User.try_to_login(params[:login], params[:password])
if user if user
self.logged_in_user = user self.logged_in_user = user
redirect_back_or_default :controller => 'my', :action => 'page' redirect_back_or_default :controller => 'my', :action => 'page'
else else
flash.now[:notice] = l(:notice_account_invalid_creditentials) flash.now[:notice] = l(:notice_account_invalid_creditentials)
end end
end end
end end
# Log out current user and redirect to welcome page # Log out current user and redirect to welcome page
def logout def logout
self.logged_in_user = nil self.logged_in_user = nil
redirect_to :controller => 'welcome' redirect_to :controller => 'welcome'
end end
# Enable user to choose a new password # Enable user to choose a new password
def lost_password def lost_password
redirect_to :controller => 'welcome' and return unless Setting.lost_password? redirect_to :controller => 'welcome' and return unless Setting.lost_password?
if params[:token] if params[:token]
@token = Token.find_by_action_and_value("recovery", params[:token]) @token = Token.find_by_action_and_value("recovery", params[:token])
redirect_to :controller => 'welcome' and return unless @token and !@token.expired? redirect_to :controller => 'welcome' and return unless @token and !@token.expired?
@user = @token.user @user = @token.user
if request.post? if request.post?
@user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation]
if @user.save if @user.save
@token.destroy @token.destroy
flash[:notice] = l(:notice_account_password_updated) flash[:notice] = l(:notice_account_password_updated)
redirect_to :action => 'login' redirect_to :action => 'login'
return return
end end
end end
render :template => "account/password_recovery" render :template => "account/password_recovery"
return return
else else
if request.post? if request.post?
user = User.find_by_mail(params[:mail]) user = User.find_by_mail(params[:mail])
# user not found in db # user not found in db
flash.now[:notice] = l(:notice_account_unknown_email) and return unless user flash.now[:notice] = l(:notice_account_unknown_email) and return unless user
# user uses an external authentification # user uses an external authentification
flash.now[:notice] = l(:notice_can_t_change_password) and return if user.auth_source_id flash.now[:notice] = l(:notice_can_t_change_password) and return if user.auth_source_id
# create a new token for password recovery # create a new token for password recovery
token = Token.new(:user => user, :action => "recovery") token = Token.new(:user => user, :action => "recovery")
if token.save if token.save
Mailer.deliver_lost_password(token) Mailer.deliver_lost_password(token)
flash[:notice] = l(:notice_account_lost_email_sent) flash[:notice] = l(:notice_account_lost_email_sent)
redirect_to :action => 'login' redirect_to :action => 'login'
return return
end end
end end
end end
end end
# User self-registration # User self-registration
def register def register
redirect_to :controller => 'welcome' and return unless Setting.self_registration? redirect_to :controller => 'welcome' and return unless Setting.self_registration?
if params[:token] if params[:token]
token = Token.find_by_action_and_value("register", params[:token]) token = Token.find_by_action_and_value("register", params[:token])
redirect_to :controller => 'welcome' and return unless token and !token.expired? redirect_to :controller => 'welcome' and return unless token and !token.expired?
user = token.user user = token.user
redirect_to :controller => 'welcome' and return unless user.status == User::STATUS_REGISTERED redirect_to :controller => 'welcome' and return unless user.status == User::STATUS_REGISTERED
user.status = User::STATUS_ACTIVE user.status = User::STATUS_ACTIVE
if user.save if user.save
token.destroy token.destroy
flash[:notice] = l(:notice_account_activated) flash[:notice] = l(:notice_account_activated)
redirect_to :action => 'login' redirect_to :action => 'login'
return return
end end
else else
if request.get? if request.get?
@user = User.new(:language => Setting.default_language) @user = User.new(:language => Setting.default_language)
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
else else
@user = User.new(params[:user]) @user = User.new(params[:user])
@user.admin = false @user.admin = false
@user.login = params[:user][:login] @user.login = params[:user][:login]
@user.status = User::STATUS_REGISTERED @user.status = User::STATUS_REGISTERED
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] @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]) } @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 @user.custom_values = @custom_values
token = Token.new(:user => @user, :action => "register") token = Token.new(:user => @user, :action => "register")
if @user.save and token.save if @user.save and token.save
Mailer.deliver_register(token) Mailer.deliver_register(token)
flash[:notice] = l(:notice_account_register_done) flash[:notice] = l(:notice_account_register_done)
redirect_to :controller => 'welcome' and return redirect_to :controller => 'welcome' and return
end end
end end
end end
end end
end end
+54 -59
View File
@@ -1,60 +1,55 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class AdminController < ApplicationController class AdminController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
helper :sort helper :sort
include SortHelper include SortHelper
def index def index
end end
def projects def projects
sort_init 'name', 'asc' sort_init 'name', 'asc'
sort_update sort_update
@project_count = Project.count @project_count = Project.count
@project_pages = Paginator.new self, @project_count, @project_pages = Paginator.new self, @project_count,
15, 15,
params['page'] params['page']
@projects = Project.find :all, :order => sort_clause, @projects = Project.find :all, :order => sort_clause,
:limit => @project_pages.items_per_page, :limit => @project_pages.items_per_page,
:offset => @project_pages.current.offset :offset => @project_pages.current.offset
render :action => "projects", :layout => false if request.xhr? render :action => "projects", :layout => false if request.xhr?
end end
def mail_options def mail_options
@actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || [] @actions = Permission.find(:all, :conditions => ["mail_option=?", true]) || []
if request.post? if request.post?
@actions.each { |a| @actions.each { |a|
a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s a.mail_enabled = (params[:action_ids] || []).include? a.id.to_s
a.save a.save
} }
flash.now[:notice] = l(:notice_successful_update) flash.now[:notice] = l(:notice_successful_update)
end end
end end
def info def info
@db_adapter_name = ActiveRecord::Base.connection.adapter_name end
@flags = Hash.new
@flags[:default_admin_changed] = User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?
@flags[:file_repository_writable] = File.writable?(Attachment.storage_path)
@flags[:textile_available] = ActionView::Helpers::TextHelper.method_defined? "textilize"
end
end end
+116 -132
View File
@@ -1,110 +1,94 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ApplicationController < ActionController::Base class ApplicationController < ActionController::Base
before_filter :check_if_login_required, :set_localization before_filter :check_if_login_required, :set_localization
filter_parameter_logging :password
def logged_in_user=(user)
def logged_in_user=(user) @logged_in_user = user
@logged_in_user = user session[:user_id] = (user ? user.id : nil)
session[:user_id] = (user ? user.id : nil) end
end
def logged_in_user
def logged_in_user if session[:user_id]
if session[:user_id] @logged_in_user ||= User.find(session[:user_id])
@logged_in_user ||= User.find(session[:user_id]) else
else nil
nil end
end end
end
# check if login is globally required to access the application
# Returns the role that the logged in user has on the current project def check_if_login_required
# or nil if current user is not a member of the project require_login if Setting.login_required?
def logged_in_user_membership end
@user_membership ||= logged_in_user.role_for_project(@project)
end def set_localization
lang = begin
# check if login is globally required to access the application if self.logged_in_user and self.logged_in_user.language and !self.logged_in_user.language.empty? and GLoc.valid_languages.include? self.logged_in_user.language.to_sym
def check_if_login_required self.logged_in_user.language
require_login if Setting.login_required? elsif request.env['HTTP_ACCEPT_LANGUAGE']
end accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first
if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym
def set_localization accept_lang
lang = begin end
if self.logged_in_user and self.logged_in_user.language and !self.logged_in_user.language.empty? and GLoc.valid_languages.include? self.logged_in_user.language.to_sym end
self.logged_in_user.language rescue
elsif request.env['HTTP_ACCEPT_LANGUAGE'] nil
accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first.split('-').first end || Setting.default_language
if accept_lang and !accept_lang.empty? and GLoc.valid_languages.include? accept_lang.to_sym set_language_if_valid(lang)
accept_lang end
end
end def require_login
rescue unless self.logged_in_user
nil store_location
end || Setting.default_language redirect_to :controller => "account", :action => "login"
set_language_if_valid(lang) return false
end end
true
def require_login end
unless self.logged_in_user
store_location def require_admin
redirect_to :controller => "account", :action => "login" return unless require_login
return false unless self.logged_in_user.admin?
end render :nothing => true, :status => 403
true return false
end end
true
def require_admin end
return unless require_login
unless self.logged_in_user.admin? # authorizes the user for the requested action.
render :nothing => true, :status => 403 def authorize(ctrl = params[:controller], action = params[:action])
return false # check if action is allowed on public projects
end if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ ctrl, action ]
true return true
end end
# if action is not public, force login
# authorizes the user for the requested action. return unless require_login
def authorize(ctrl = params[:controller], action = params[:action]) # admin is always authorized
# check if action is allowed on public projects return true if self.logged_in_user.admin?
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ ctrl, action ] # if not admin, check membership permission
return true @user_membership ||= Member.find(:first, :conditions => ["user_id=? and project_id=?", self.logged_in_user.id, @project.id])
end if @user_membership and Permission.allowed_to_role( "%s/%s" % [ ctrl, action ], @user_membership.role_id )
# if action is not public, force login return true
return unless require_login end
# admin is always authorized render :nothing => true, :status => 403
return true if self.logged_in_user.admin? false
# if not admin, check membership permission end
if logged_in_user_membership and Permission.allowed_to_role( "%s/%s" % [ ctrl, action ], logged_in_user_membership )
return true
end
render :nothing => true, :status => 403
false
end
# make sure that the user is a member of the project (or admin) if project is private
# used as a before_filter for actions that do not require any particular permission on the project
def check_project_privacy
return true if @project.is_public?
return false unless logged_in_user
return true if logged_in_user.admin? || logged_in_user_membership
render :nothing => true, :status => 403
false
end
# store current uri in session. # store current uri in session.
# return to this location by calling redirect_back_or_default # return to this location by calling redirect_back_or_default
def store_location def store_location
@@ -119,30 +103,30 @@ class ApplicationController < ActionController::Base
redirect_to session[:return_to_params] redirect_to session[:return_to_params]
session[:return_to_params] = nil session[:return_to_params] = nil
end end
end
def render_404
@html_title = "404"
render :template => "common/404", :layout => true, :status => 404
return false
end end
def render_404 # qvalues http header parser
@html_title = "404" # code taken from webrick
render :template => "common/404", :layout => true, :status => 404 def parse_qvalues(value)
return false tmp = []
end if value
parts = value.split(/,\s*/)
# qvalues http header parser parts.each {|part|
# code taken from webrick if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part)
def parse_qvalues(value) val = m[1]
tmp = [] q = (m[2] or 1).to_f
if value tmp.push([val, q])
parts = value.split(/,\s*/) end
parts.each {|part| }
if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) tmp = tmp.sort_by{|val, q| -q}
val = m[1] tmp.collect!{|val, q| val}
q = (m[2] or 1).to_f end
tmp.push([val, q]) return tmp
end end
}
tmp = tmp.sort_by{|val, q| -q}
tmp.collect!{|val, q| val}
end
return tmp
end
end end
+59 -59
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomFieldsController < ApplicationController class CustomFieldsController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
def index def index
list list
@@ -25,48 +25,48 @@ class CustomFieldsController < ApplicationController
end end
def list def list
@custom_fields_by_type = CustomField.find(:all).group_by {|f| f.type.to_s } @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.type.to_s }
@tab = params[:tab] || 'IssueCustomField' @tab = params[:tab] || 'IssueCustomField'
render :action => "list", :layout => false if request.xhr? render :action => "list", :layout => false if request.xhr?
end end
def new def new
case params[:type] case params[:type]
when "IssueCustomField" when "IssueCustomField"
@custom_field = IssueCustomField.new(params[:custom_field]) @custom_field = IssueCustomField.new(params[:custom_field])
@custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids] @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids]
when "UserCustomField" when "UserCustomField"
@custom_field = UserCustomField.new(params[:custom_field]) @custom_field = UserCustomField.new(params[:custom_field])
when "ProjectCustomField" when "ProjectCustomField"
@custom_field = ProjectCustomField.new(params[:custom_field]) @custom_field = ProjectCustomField.new(params[:custom_field])
else else
redirect_to :action => 'list' redirect_to :action => 'list'
return return
end end
if request.post? and @custom_field.save if request.post? and @custom_field.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'list', :tab => @custom_field.type redirect_to :action => 'list', :tab => @custom_field.type
end end
@trackers = Tracker.find(:all, :order => 'position') @trackers = Tracker.find(:all, :order => 'position')
end end
def edit def edit
@custom_field = CustomField.find(params[:id]) @custom_field = CustomField.find(params[:id])
if request.post? and @custom_field.update_attributes(params[:custom_field]) if request.post? and @custom_field.update_attributes(params[:custom_field])
if @custom_field.is_a? IssueCustomField if @custom_field.is_a? IssueCustomField
@custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : [] @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : []
end end
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list', :tab => @custom_field.type redirect_to :action => 'list', :tab => @custom_field.type
end end
@trackers = Tracker.find(:all, :order => 'position') @trackers = Tracker.find(:all, :order => 'position')
end end
def destroy def destroy
@custom_field = CustomField.find(params[:id]).destroy @custom_field = CustomField.find(params[:id]).destroy
redirect_to :action => 'list', :tab => @custom_field.type redirect_to :action => 'list', :tab => @custom_field.type
rescue rescue
flash[:notice] = "Unable to delete custom field" flash[:notice] = "Unable to delete custom field"
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
+55 -55
View File
@@ -1,71 +1,71 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class DocumentsController < ApplicationController
layout 'base'
before_filter :find_project, :authorize
class DocumentsController < ApplicationController def show
layout 'base'
before_filter :find_project, :authorize
def show
@attachments = @document.attachments.find(:all, :order => "created_on DESC") @attachments = @document.attachments.find(:all, :order => "created_on DESC")
end end
def edit def edit
@categories = Enumeration::get_values('DCAT') @categories = Enumeration::get_values('DCAT')
if request.post? and @document.update_attributes(params[:document]) if request.post? and @document.update_attributes(params[:document])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @document redirect_to :action => 'show', :id => @document
end end
end end
def destroy def destroy
@document.destroy @document.destroy
redirect_to :controller => 'projects', :action => 'list_documents', :id => @project redirect_to :controller => 'projects', :action => 'list_documents', :id => @project
end
def download
@attachment = @document.attachments.find(params[:attachment_id])
@attachment.increment_download
send_file @attachment.diskfile, :filename => @attachment.filename
rescue
render_404
end
def add_attachment
# Save the attachments
@attachments = []
params[:attachments].each { |file|
next unless file.size > 0
a = Attachment.create(:container => @document, :file => file, :author => logged_in_user)
@attachments << a unless a.new_record?
} if params[:attachments] and params[:attachments].is_a? Array
Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
redirect_to :action => 'show', :id => @document
end
def destroy_attachment
@document.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'show', :id => @document
end end
def download private
@attachment = @document.attachments.find(params[:attachment_id]) def find_project
@attachment.increment_download @document = Document.find(params[:id])
send_file @attachment.diskfile, :filename => @attachment.filename @project = @document.project
rescue rescue ActiveRecord::RecordNotFound
render_404 render_404
end
def add_attachment
# Save the attachments
@attachments = []
params[:attachments].each { |file|
next unless file.size > 0
a = Attachment.create(:container => @document, :file => file, :author => logged_in_user)
@attachments << a unless a.new_record?
} if params[:attachments] and params[:attachments].is_a? Array
Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
redirect_to :action => 'show', :id => @document
end
def destroy_attachment
@document.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'show', :id => @document
end
private
def find_project
@document = Document.find(params[:id])
@project = @document.project
rescue ActiveRecord::RecordNotFound
render_404
end end
end end
+24 -24
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class EnumerationsController < ApplicationController class EnumerationsController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
def index def index
list list
@@ -60,11 +60,11 @@ class EnumerationsController < ApplicationController
end end
def destroy def destroy
Enumeration.find(params[:id]).destroy Enumeration.find(params[:id]).destroy
flash[:notice] = l(:notice_successful_delete) flash[:notice] = l(:notice_successful_delete)
redirect_to :action => 'list' redirect_to :action => 'list'
rescue rescue
flash[:notice] = "Unable to delete enumeration" flash[:notice] = "Unable to delete enumeration"
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
+3 -74
View File
@@ -1,5 +1,5 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -16,81 +16,10 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class FeedsController < ApplicationController class FeedsController < ApplicationController
before_filter :find_scope
session :off session :off
helper :issues
include IssuesHelper
helper :custom_fields
include CustomFieldsHelper
# news feeds
def news def news
News.with_scope(:find => @find_options) do @news = News.find :all, :order => 'news.created_on DESC', :limit => 10, :include => [ :author, :project ]
@news = News.find :all, :order => "#{News.table_name}.created_on DESC", :include => [ :author, :project ]
end
headers["Content-Type"] = "application/rss+xml" headers["Content-Type"] = "application/rss+xml"
render :action => 'news_atom' if 'atom' == params[:format]
end
# issue feeds
def issues
if @project && params[:query_id]
query = Query.find(params[:query_id])
# ignore query if it's not valid
query = nil unless query.valid?
# override with query conditions
@find_options[:conditions] = query.statement if query.valid? and @project == query.project
end
Issue.with_scope(:find => @find_options) do
@issues = Issue.find :all, :include => [:project, :author, :tracker, :status],
:order => "#{Issue.table_name}.created_on DESC"
end
@title = (@project ? @project.name : Setting.app_title) + ": " + (query ? query.name : l(:label_reported_issues))
headers["Content-Type"] = "application/rss+xml"
render :action => 'issues_atom' if 'atom' == params[:format]
end
# issue changes feeds
def history
if @project && params[:query_id]
query = Query.find(params[:query_id])
# ignore query if it's not valid
query = nil unless query.valid?
# override with query conditions
@find_options[:conditions] = query.statement if query.valid? and @project == query.project
end
Journal.with_scope(:find => @find_options) do
@journals = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ],
:order => "#{Journal.table_name}.created_on DESC"
end
@title = (@project ? @project.name : Setting.app_title) + ": " + (query ? query.name : l(:label_reported_issues))
headers["Content-Type"] = "application/rss+xml"
render :action => 'history_atom' if 'atom' == params[:format]
end
private
# override for feeds specific authentication
def check_if_login_required
@user = User.find_by_rss_key(params[:key])
render(:nothing => true, :status => 403) and return false if !@user && Setting.login_required?
end
def find_scope
if params[:project_id]
# project feed
# check if project is public or if the user is a member
@project = Project.find(params[:project_id])
render(:nothing => true, :status => 403) and return false unless @project.is_public? || (@user && @user.role_for_project(@project))
scope = ["#{Project.table_name}.id=?", params[:project_id].to_i]
else
# global feed
scope = ["#{Project.table_name}.is_public=?", true]
end
@find_options = {:conditions => scope, :limit => Setting.feeds_limit}
return true
end end
end end
+45 -42
View File
@@ -1,44 +1,47 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class HelpController < ApplicationController class HelpController < ApplicationController
skip_before_filter :check_if_login_required skip_before_filter :check_if_login_required
before_filter :load_help_config before_filter :load_help_config
# displays help page for the requested controller/action # displays help page for the requested controller/action
def index def index
# select help page to display # select help page to display
if params[:ctrl] and @help_config['pages'][params[:ctrl]] if params[:ctrl] and @help_config['pages'][params[:ctrl]]
if params[:page] and @help_config['pages'][params[:ctrl]][params[:page]] if params[:page] and @help_config['pages'][params[:ctrl]][params[:page]]
template = @help_config['pages'][params[:ctrl]][params[:page]] template = @help_config['pages'][params[:ctrl]][params[:page]]
else else
template = @help_config['pages'][params[:ctrl]]['index'] template = @help_config['pages'][params[:ctrl]]['index']
end end
end end
# choose language according to available help translations # choose language according to available help translations
lang = (@help_config['langs'].include? current_language.to_s) ? current_language.to_s : @help_config['langs'].first lang = (@help_config['langs'].include? current_language.to_s) ? current_language.to_s : @help_config['langs'].first
url = "/manual/#{lang}/" + (template || "index.html") if template
redirect_to(request.relative_url_root + url) redirect_to "/manual/#{lang}/#{template}"
end else
redirect_to "/manual/#{lang}/index.html"
private end
def load_help_config end
@help_config = YAML::load(File.open("#{RAILS_ROOT}/config/help.yml"))
private
def load_help_config
@help_config = YAML::load(File.open("#{RAILS_ROOT}/config/help.yml"))
end end
end end
+31 -31
View File
@@ -1,24 +1,24 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueCategoriesController < ApplicationController class IssueCategoriesController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project, :authorize before_filter :find_project, :authorize
def edit def edit
if request.post? and @category.update_attributes(params[:category]) if request.post? and @category.update_attributes(params[:category])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
@@ -28,17 +28,17 @@ class IssueCategoriesController < ApplicationController
def destroy def destroy
@category.destroy @category.destroy
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
rescue rescue
flash[:notice] = "Categorie can't be deleted" flash[:notice] = "Categorie can't be deleted"
redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project
end end
private private
def find_project def find_project
@category = IssueCategory.find(params[:id]) @category = IssueCategory.find(params[:id])
@project = @category.project @project = @category.project
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
end end
+42 -42
View File
@@ -1,34 +1,34 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueStatusesController < ApplicationController class IssueStatusesController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
verify :method => :post, :only => [ :destroy, :create, :update, :move ], verify :method => :post, :only => [ :destroy, :create, :update, :move ],
:redirect_to => { :action => :list } :redirect_to => { :action => :list }
def index def index
list list
render :action => 'list' unless request.xhr? render :action => 'list' unless request.xhr?
end end
def list def list
@issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position" @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position"
render :action => "list", :layout => false if request.xhr? render :action => "list", :layout => false if request.xhr?
end end
@@ -58,28 +58,28 @@ class IssueStatusesController < ApplicationController
else else
render :action => 'edit' render :action => 'edit'
end end
end end
def move def move
@issue_status = IssueStatus.find(params[:id]) @issue_status = IssueStatus.find(params[:id])
case params[:position] case params[:position]
when 'highest' when 'highest'
@issue_status.move_to_top @issue_status.move_to_top
when 'higher' when 'higher'
@issue_status.move_higher @issue_status.move_higher
when 'lower' when 'lower'
@issue_status.move_lower @issue_status.move_lower
when 'lowest' when 'lowest'
@issue_status.move_to_bottom @issue_status.move_to_bottom
end if params[:position] end if params[:position]
redirect_to :action => 'list' redirect_to :action => 'list'
end end
def destroy def destroy
IssueStatus.find(params[:id]).destroy IssueStatus.find(params[:id]).destroy
redirect_to :action => 'list' redirect_to :action => 'list'
rescue rescue
flash[:notice] = "Unable to delete issue status" flash[:notice] = "Unable to delete issue status"
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
+135 -145
View File
@@ -1,159 +1,149 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssuesController < ApplicationController class IssuesController < ApplicationController
layout 'base', :except => :export_pdf layout 'base', :except => :export_pdf
before_filter :find_project, :authorize before_filter :find_project, :authorize
helper :custom_fields helper :custom_fields
include CustomFieldsHelper include CustomFieldsHelper
helper :ifpdf helper :ifpdf
include IfpdfHelper include IfpdfHelper
def show def show
@status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user @status_options = @issue.status.workflows.find(:all, :order => 'position', :include => :new_status, :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) @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
@journals_count = @issue.journals.count @journals_count = @issue.journals.count
@journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "#{Journal.table_name}.created_on desc") @journals = @issue.journals.find(:all, :include => [:user, :details], :limit => 15, :order => "journals.created_on desc")
end end
def history def history
@journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on desc") @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "journals.created_on desc")
@journals_count = @journals.length @journals_count = @journals.length
end end
def export_pdf def export_pdf
@custom_values = @issue.custom_values.find(:all, :include => :custom_field) @custom_values = @issue.custom_values.find(:all, :include => :custom_field)
@options_for_rfpdf ||= {} @options_for_rfpdf ||= {}
@options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf" @options_for_rfpdf[:file_name] = "#{@project.name}_#{@issue.long_id}.pdf"
end end
def edit def edit
@priorities = Enumeration::get_values('IPRI') @priorities = Enumeration::get_values('IPRI')
if request.get? if request.get?
@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) } @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 else
begin begin
@issue.init_journal(self.logged_in_user) @issue.init_journal(self.logged_in_user)
# Retrieve custom fields and values # Retrieve custom fields and values
@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]) } @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 @issue.custom_values = @custom_values
@issue.attributes = params[:issue] @issue.attributes = params[:issue]
if @issue.save if @issue.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @issue redirect_to :action => 'show', :id => @issue
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
# Optimistic locking exception # Optimistic locking exception
flash[:notice] = l(:notice_locking_conflict) flash[:notice] = l(:notice_locking_conflict)
end end
end end
end end
def add_note def add_note
unless params[:notes].empty? unless params[:notes].empty?
journal = @issue.init_journal(self.logged_in_user, params[:notes]) journal = @issue.init_journal(self.logged_in_user, params[:notes])
if @issue.save #@history = @issue.histories.build(params[:history])
flash[:notice] = l(:notice_successful_update) #@history.author_id = self.logged_in_user.id if self.logged_in_user
Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled? #@history.status = @issue.status
redirect_to :action => 'show', :id => @issue if @issue.save
return flash[:notice] = l(:notice_successful_update)
end Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
end redirect_to :action => 'show', :id => @issue
show return
render :action => 'show' end
end end
show
def change_status render :action => 'show'
@status_options = @issue.status.find_new_statuses_allowed_to(logged_in_user.role_for_project(@project), @issue.tracker) if logged_in_user end
@new_status = IssueStatus.find(params[:new_status_id])
if params[:confirm] def change_status
begin #@history = @issue.histories.build(params[:history])
journal = @issue.init_journal(self.logged_in_user, params[:notes]) @status_options = @issue.status.workflows.find(:all, :order => 'position', :include => :new_status, :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
@issue.status = @new_status @new_status = IssueStatus.find(params[:new_status_id])
if @issue.update_attributes(params[:issue]) if params[:confirm]
# Save attachments begin
params[:attachments].each { |file| #@history.author_id = self.logged_in_user.id if self.logged_in_user
next unless file.size > 0 #@issue.status = @history.status
a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user) #@issue.fixed_version_id = (params[:issue][:fixed_version_id])
journal.details << JournalDetail.new(:property => 'attachment', #@issue.assigned_to_id = (params[:issue][:assigned_to_id])
:prop_key => a.id, #@issue.done_ratio = (params[:issue][:done_ratio])
:value => a.filename) unless a.new_record? #@issue.lock_version = (params[:issue][:lock_version])
} if params[:attachments] and params[:attachments].is_a? Array journal = @issue.init_journal(self.logged_in_user, params[:notes])
@issue.status = @new_status
flash[:notice] = l(:notice_successful_update) if @issue.update_attributes(params[:issue])
Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled? flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @issue Mailer.deliver_issue_edit(journal) if Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
end redirect_to :action => 'show', :id => @issue
rescue ActiveRecord::StaleObjectError end
# Optimistic locking exception rescue ActiveRecord::StaleObjectError
flash[:notice] = l(:notice_locking_conflict) # Optimistic locking exception
end flash[:notice] = l(:notice_locking_conflict)
end end
@assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user } end
@assignable_to = @project.members.find(:all, :include => :user).collect{ |m| m.user }
end end
def destroy def destroy
@issue.destroy @issue.destroy
redirect_to :controller => 'projects', :action => 'list_issues', :id => @project redirect_to :controller => 'projects', :action => 'list_issues', :id => @project
end end
def add_attachment def add_attachment
# Save the attachments # Save the attachments
@attachments = [] @attachments = []
journal = @issue.init_journal(self.logged_in_user) params[:attachments].each { |file|
params[:attachments].each { |file| next unless file.size > 0
next unless file.size > 0 a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user)
a = Attachment.create(:container => @issue, :file => file, :author => logged_in_user) @attachments << a unless a.new_record?
@attachments << a unless a.new_record? } if params[:attachments] and params[:attachments].is_a? Array
journal.details << JournalDetail.new(:property => 'attachment', Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled?
:prop_key => a.id, redirect_to :action => 'show', :id => @issue
:value => a.filename) unless a.new_record? end
} if params[:attachments] and params[:attachments].is_a? Array
journal.save if journal.details.any? def destroy_attachment
Mailer.deliver_attachments_add(@attachments) if !@attachments.empty? and Permission.find_by_controller_and_action(params[:controller], params[:action]).mail_enabled? @issue.attachments.find(params[:attachment_id]).destroy
redirect_to :action => 'show', :id => @issue redirect_to :action => 'show', :id => @issue
end end
def destroy_attachment # Send the file in stream mode
a = @issue.attachments.find(params[:attachment_id]) def download
a.destroy @attachment = @issue.attachments.find(params[:attachment_id])
journal = @issue.init_journal(self.logged_in_user) send_file @attachment.diskfile, :filename => @attachment.filename
journal.details << JournalDetail.new(:property => 'attachment', rescue
:prop_key => a.id, render_404
:old_value => a.filename) end
journal.save
redirect_to :action => 'show', :id => @issue private
end def find_project
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
# Send the file in stream mode @project = @issue.project
def download @html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
@attachment = @issue.attachments.find(params[:attachment_id]) rescue ActiveRecord::RecordNotFound
send_file @attachment.diskfile, :filename => @attachment.filename render_404
rescue
render_404
end
private
def find_project
@issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category])
@project = @issue.project
@html_title = "#{@project.name} - #{@issue.tracker.name} ##{@issue.id}"
rescue ActiveRecord::RecordNotFound
render_404
end end
end end
+31 -31
View File
@@ -1,42 +1,42 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class MembersController < ApplicationController class MembersController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project, :authorize before_filter :find_project, :authorize
def edit def edit
if request.post? and @member.update_attributes(params[:member]) if request.post? and @member.update_attributes(params[:member])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project
end end
end end
def destroy def destroy
@member.destroy @member.destroy
flash[:notice] = l(:notice_successful_delete) flash[:notice] = l(:notice_successful_delete)
redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project
end end
private private
def find_project def find_project
@member = Member.find(params[:id]) @member = Member.find(params[:id])
@project = @member.project @project = @member.project
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
end end
+1 -2
View File
@@ -90,9 +90,8 @@ class MyController < ApplicationController
# The block is added on top of the page # The block is added on top of the page
# params[:block] : id of the block to add # params[:block] : id of the block to add
def add_block def add_block
block = params[:block]
render(:nothing => true) and return unless block && (BLOCKS.keys.include? block)
@user = self.logged_in_user @user = self.logged_in_user
block = params[:block]
# remove if already present in a group # remove if already present in a group
%w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block } %w(top left right).each {|f| (session[:page_layout][f] ||= []).delete block }
# add it on top # add it on top
+44 -44
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class NewsController < ApplicationController class NewsController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project, :authorize before_filter :find_project, :authorize
def show def show
end end
@@ -27,34 +27,34 @@ class NewsController < ApplicationController
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'show', :id => @news redirect_to :action => 'show', :id => @news
end end
end
def add_comment
@comment = Comment.new(params[:comment])
@comment.author = logged_in_user
if @news.comments << @comment
flash[:notice] = l(:label_comment_added)
redirect_to :action => 'show', :id => @news
else
render :action => 'show'
end
end end
def add_comment def destroy_comment
@comment = Comment.new(params[:comment]) @news.comments.find(params[:comment_id]).destroy
@comment.author = logged_in_user redirect_to :action => 'show', :id => @news
if @news.comments << @comment end
flash[:notice] = l(:label_comment_added)
redirect_to :action => 'show', :id => @news
else
render :action => 'show'
end
end
def destroy_comment
@news.comments.find(params[:comment_id]).destroy
redirect_to :action => 'show', :id => @news
end
def destroy def destroy
@news.destroy @news.destroy
redirect_to :controller => 'projects', :action => 'list_news', :id => @project redirect_to :controller => 'projects', :action => 'list_news', :id => @project
end end
private private
def find_project def find_project
@news = News.find(params[:id]) @news = News.find(params[:id])
@project = @news.project @project = @news.project
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
end end
File diff suppressed because it is too large. Load diff
+165 -189
View File
@@ -1,191 +1,167 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ReportsController < ApplicationController class ReportsController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project, :authorize before_filter :find_project, :authorize
def issue_report def issue_report
@statuses = IssueStatus.find(:all, :order => 'position') @statuses = IssueStatus.find(:all, :order => 'position')
case params[:detail] case params[:detail]
when "tracker" when "tracker"
@field = "tracker_id" @field = "tracker_id"
@rows = Tracker.find :all, :order => 'position' @rows = Tracker.find :all, :order => 'position'
@data = issues_by_tracker @data = issues_by_tracker
@report_title = l(:field_tracker) @report_title = l(:field_tracker)
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
when "priority" when "priority"
@field = "priority_id" @field = "priority_id"
@rows = Enumeration::get_values('IPRI') @rows = Enumeration::get_values('IPRI')
@data = issues_by_priority @data = issues_by_priority
@report_title = l(:field_priority) @report_title = l(:field_priority)
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
when "category" when "category"
@field = "category_id" @field = "category_id"
@rows = @project.issue_categories @rows = @project.issue_categories
@data = issues_by_category @data = issues_by_category
@report_title = l(:field_category) @report_title = l(:field_category)
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
when "author" when "author"
@field = "author_id" @field = "author_id"
@rows = @project.members.collect { |m| m.user } @rows = @project.members.collect { |m| m.user }
@data = issues_by_author @data = issues_by_author
@report_title = l(:field_author) @report_title = l(:field_author)
render :template => "reports/issue_report_details" render :template => "reports/issue_report_details"
when "subproject" else
@field = "project_id" @queries = @project.queries.find :all, :conditions => ["is_public=? or user_id=?", true, (logged_in_user ? logged_in_user.id : 0)]
@rows = @project.children @trackers = Tracker.find(:all, :order => 'position')
@data = issues_by_subproject @priorities = Enumeration::get_values('IPRI')
@report_title = l(:field_subproject) @categories = @project.issue_categories
render :template => "reports/issue_report_details" @authors = @project.members.collect { |m| m.user }
else issues_by_tracker
@queries = @project.queries.find :all, :conditions => ["is_public=? or user_id=?", true, (logged_in_user ? logged_in_user.id : 0)] issues_by_priority
@trackers = Tracker.find(:all, :order => 'position') issues_by_category
@priorities = Enumeration::get_values('IPRI') issues_by_author
@categories = @project.issue_categories render :template => "reports/issue_report"
@authors = @project.members.collect { |m| m.user } end
@subprojects = @project.children end
issues_by_tracker
issues_by_priority def delays
issues_by_category @trackers = Tracker.find(:all)
issues_by_author if request.get?
issues_by_subproject @selected_tracker_ids = @trackers.collect {|t| t.id.to_s }
@total_hours = @project.time_entries.sum(:hours) else
render :template => "reports/issue_report" @selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array
end end
end @selected_tracker_ids ||= []
@raw =
def delays ActiveRecord::Base.connection.select_all("SELECT datediff( a.created_on, b.created_on ) as delay, count(a.id) as total
@trackers = Tracker.find(:all) FROM issue_histories a, issue_histories b, issues i
if request.get? WHERE a.status_id =5
@selected_tracker_ids = @trackers.collect {|t| t.id.to_s } AND a.issue_id = b.issue_id
else AND a.issue_id = i.id
@selected_tracker_ids = params[:tracker_ids].collect { |id| id.to_i.to_s } if params[:tracker_ids] and params[:tracker_ids].is_a? Array AND i.tracker_id in (#{@selected_tracker_ids.join(',')})
end AND b.id = (
@selected_tracker_ids ||= [] SELECT min( c.id )
@raw = FROM issue_histories c
ActiveRecord::Base.connection.select_all("SELECT datediff( a.created_on, b.created_on ) as delay, count(a.id) as total WHERE b.issue_id = c.issue_id )
FROM issue_histories a, issue_histories b, issues i GROUP BY delay") unless @selected_tracker_ids.empty?
WHERE a.status_id =5 @raw ||=[]
AND a.issue_id = b.issue_id
AND a.issue_id = i.id @x_from = 0
AND i.tracker_id in (#{@selected_tracker_ids.join(',')}) @x_to = 0
AND b.id = ( @y_from = 0
SELECT min( c.id ) @y_to = 0
FROM issue_histories c @sum_total = 0
WHERE b.issue_id = c.issue_id ) @sum_delay = 0
GROUP BY delay") unless @selected_tracker_ids.empty? @raw.each do |r|
@raw ||=[] @x_to = [r['delay'].to_i, @x_to].max
@y_to = [r['total'].to_i, @y_to].max
@x_from = 0 @sum_total = @sum_total + r['total'].to_i
@x_to = 0 @sum_delay = @sum_delay + r['total'].to_i * r['delay'].to_i
@y_from = 0 end
@y_to = 0 end
@sum_total = 0
@sum_delay = 0 private
@raw.each do |r| # Find project of id params[:id]
@x_to = [r['delay'].to_i, @x_to].max def find_project
@y_to = [r['total'].to_i, @y_to].max @project = Project.find(params[:id])
@sum_total = @sum_total + r['total'].to_i rescue ActiveRecord::RecordNotFound
@sum_delay = @sum_delay + r['total'].to_i * r['delay'].to_i render_404
end end
end
def issues_by_tracker
private @issues_by_tracker ||=
# Find project of id params[:id] ActiveRecord::Base.connection.select_all("select s.id as status_id,
def find_project s.is_closed as closed,
@project = Project.find(params[:id]) t.id as tracker_id,
rescue ActiveRecord::RecordNotFound count(i.id) as total
render_404 from
end issues i, issue_statuses s, trackers t
where
def issues_by_tracker i.status_id=s.id
@issues_by_tracker ||= and i.tracker_id=t.id
ActiveRecord::Base.connection.select_all("select s.id as status_id, and i.project_id=#{@project.id}
s.is_closed as closed, group by s.id, s.is_closed, t.id")
t.id as tracker_id, end
count(i.id) as total
from def issues_by_priority
#{Issue.table_name} i, #{IssueStatus.table_name} s, #{Tracker.table_name} t @issues_by_priority ||=
where ActiveRecord::Base.connection.select_all("select s.id as status_id,
i.status_id=s.id s.is_closed as closed,
and i.tracker_id=t.id p.id as priority_id,
and i.project_id=#{@project.id} count(i.id) as total
group by s.id, s.is_closed, t.id") from
end issues i, issue_statuses s, enumerations p
where
def issues_by_priority i.status_id=s.id
@issues_by_priority ||= and i.priority_id=p.id
ActiveRecord::Base.connection.select_all("select s.id as status_id, and i.project_id=#{@project.id}
s.is_closed as closed, group by s.id, s.is_closed, p.id")
p.id as priority_id, end
count(i.id) as total
from def issues_by_category
#{Issue.table_name} i, #{IssueStatus.table_name} s, #{Enumeration.table_name} p @issues_by_category ||=
where ActiveRecord::Base.connection.select_all("select s.id as status_id,
i.status_id=s.id s.is_closed as closed,
and i.priority_id=p.id c.id as category_id,
and i.project_id=#{@project.id} count(i.id) as total
group by s.id, s.is_closed, p.id") from
end issues i, issue_statuses s, issue_categories c
where
def issues_by_category i.status_id=s.id
@issues_by_category ||= and i.category_id=c.id
ActiveRecord::Base.connection.select_all("select s.id as status_id, and i.project_id=#{@project.id}
s.is_closed as closed, group by s.id, s.is_closed, c.id")
c.id as category_id, end
count(i.id) as total
from def issues_by_author
#{Issue.table_name} i, #{IssueStatus.table_name} s, #{IssueCategory.table_name} c @issues_by_author ||=
where ActiveRecord::Base.connection.select_all("select s.id as status_id,
i.status_id=s.id s.is_closed as closed,
and i.category_id=c.id a.id as author_id,
and i.project_id=#{@project.id} count(i.id) as total
group by s.id, s.is_closed, c.id") from
end issues i, issue_statuses s, users a
where
def issues_by_author i.status_id=s.id
@issues_by_author ||= and i.author_id=a.id
ActiveRecord::Base.connection.select_all("select s.id as status_id, and i.project_id=#{@project.id}
s.is_closed as closed, group by s.id, s.is_closed, a.id")
a.id as author_id,
count(i.id) as total
from
#{Issue.table_name} i, #{IssueStatus.table_name} s, #{User.table_name} a
where
i.status_id=s.id
and i.author_id=a.id
and i.project_id=#{@project.id}
group by s.id, s.is_closed, a.id")
end
def issues_by_subproject
@issues_by_subproject ||=
ActiveRecord::Base.connection.select_all("select s.id as status_id,
s.is_closed as closed,
i.project_id as project_id,
count(i.id) as total
from
#{Issue.table_name} i, #{IssueStatus.table_name} s
where
i.status_id=s.id
and i.project_id IN (#{@project.children.collect{|p| p.id}.join(',')})
group by s.id, s.is_closed, i.project_id") if @project.children.any?
@issues_by_subproject ||= []
end end
end end
+11 -145
View File
@@ -1,5 +1,5 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -15,26 +15,14 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'SVG/Graph/Bar'
require 'SVG/Graph/BarHorizontal'
class RepositoriesController < ApplicationController class RepositoriesController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project before_filter :find_project, :authorize
before_filter :authorize, :except => [:stats, :graph]
before_filter :check_project_privacy, :only => [:stats, :graph]
def show def show
# get entries for the browse frame
@entries = @repository.scm.entries('') @entries = @repository.scm.entries('')
show_error and return unless @entries show_error and return unless @entries
# check if new revisions have been committed in the repository @latest_revision = @entries.revisions.latest
scm_latestrev = @entries.revisions.latest
if Setting.autofetch_changesets? && scm_latestrev && ((@repository.latest_changeset.nil?) || (@repository.latest_changeset.revision < scm_latestrev.identifier.to_i))
@repository.fetch_changesets
@repository.reload
end
@changesets = @repository.changesets.find(:all, :limit => 5, :order => "committed_on DESC")
end end
def browse def browse
@@ -43,20 +31,9 @@ class RepositoriesController < ApplicationController
end end
def revisions def revisions
unless @path == '' @entry = @repository.scm.entry(@path, @rev)
@entry = @repository.scm.entry(@path, @rev) @revisions = @repository.scm.revisions(@path, @rev)
show_error and return unless @entry show_error and return unless @entry && @revisions
end
@repository.changesets_with_path @path do
@changeset_count = @repository.changesets.count
@changeset_pages = Paginator.new self, @changeset_count,
25,
params['page']
@changesets = @repository.changesets.find(:all,
:limit => @changeset_pages.items_per_page,
:offset => @changeset_pages.current.offset)
end
render :action => "revisions", :layout => false if request.xhr?
end end
def entry def entry
@@ -68,41 +45,21 @@ class RepositoriesController < ApplicationController
end end
def revision def revision
@changeset = @repository.changesets.find_by_revision(@rev) @revisions = @repository.scm.revisions '', @rev, @rev, :with_paths => true
show_error and return unless @changeset show_error and return unless @revisions
@revision = @revisions.first
end end
def diff def diff
@rev_to = params[:rev_to] || (@rev-1) @rev_to = params[:rev_to] || (@rev-1)
type = params[:type] || 'inline' @diff = @repository.scm.diff(params[:path], @rev, @rev_to)
@diff = @repository.scm.diff(params[:path], @rev, @rev_to, type)
show_error and return unless @diff show_error and return unless @diff
end end
def stats
end
def graph
data = nil
case params[:graph]
when "commits_per_month"
data = graph_commits_per_month(@repository)
when "commits_per_author"
data = graph_commits_per_author(@repository)
end
if data
headers["Content-Type"] = "image/svg+xml"
send_data(data, :type => "image/svg+xml", :disposition => "inline")
else
render_404
end
end
private private
def find_project def find_project
@project = Project.find(params[:id]) @project = Project.find(params[:id])
@repository = @project.repository @repository = @project.repository
render_404 and return false unless @repository
@path = params[:path].squeeze('/').gsub(/^\//, '') if params[:path] @path = params[:path].squeeze('/').gsub(/^\//, '') if params[:path]
@path ||= '' @path ||= ''
@rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0 @rev = params[:rev].to_i if params[:rev] and params[:rev].to_i > 0
@@ -114,95 +71,4 @@ private
flash.now[:notice] = l(:notice_scm_error) flash.now[:notice] = l(:notice_scm_error)
render :nothing => true, :layout => true render :nothing => true, :layout => true
end end
def graph_commits_per_month(repository)
@date_to = Date.today
@date_from = @date_to << 12
commits_by_day = repository.changesets.count(:all, :group => :commit_date, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to])
commits_by_month = [0] * 12
commits_by_day.each {|c| commits_by_month[c.first.to_date.months_ago] += c.last }
changes_by_day = repository.changes.count(:all, :group => :commit_date)
changes_by_month = [0] * 12
changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last }
fields = []
month_names = l(:actionview_datehelper_select_month_names_abbr).split(',')
12.times {|m| fields << month_names[((Date.today.month - 1 - m) % 12)]}
graph = SVG::Graph::Bar.new(
:height => 300,
:width => 500,
:fields => fields.reverse,
:stack => :side,
:scale_integers => true,
:step_x_labels => 2,
:show_data_values => false,
:graph_title => l(:label_commits_per_month),
:show_graph_title => true
)
graph.add_data(
:data => commits_by_month[0..11].reverse,
:title => l(:label_revision_plural)
)
graph.add_data(
:data => changes_by_month[0..11].reverse,
:title => l(:label_change_plural)
)
graph.burn
end
def graph_commits_per_author(repository)
commits_by_author = repository.changesets.count(:all, :group => :committer)
commits_by_author.sort! {|x, y| x.last <=> y.last}
changes_by_author = repository.changes.count(:all, :group => :committer)
h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o}
fields = commits_by_author.collect {|r| r.first}
commits_data = commits_by_author.collect {|r| r.last}
changes_data = commits_by_author.collect {|r| h[r.first] || 0}
fields = fields + [""]*(10 - fields.length) if fields.length<10
commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10
changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10
graph = SVG::Graph::BarHorizontal.new(
:height => 300,
:width => 500,
:fields => fields,
:stack => :side,
:scale_integers => true,
:show_data_values => false,
:rotate_y_labels => false,
:graph_title => l(:label_commits_per_author),
:show_graph_title => true
)
graph.add_data(
:data => commits_data,
:title => l(:label_revision_plural)
)
graph.add_data(
:data => changes_data,
:title => l(:label_change_plural)
)
graph.burn
end
end
class Date
def months_ago(date = Date.today)
(date.year - self.year)*12 + (date.month - self.month)
end
def weeks_ago(date = Date.today)
(date.year - self.year)*52 + (date.cweek - self.cweek)
end
end end
+68 -81
View File
@@ -1,26 +1,26 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class RolesController < ApplicationController class RolesController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
verify :method => :post, :only => [ :destroy, :move ], verify :method => :post, :only => [ :destroy, :move ],
:redirect_to => { :action => :list } :redirect_to => { :action => :list }
def index def index
list list
@@ -28,26 +28,26 @@ class RolesController < ApplicationController
end end
def list def list
@role_pages, @roles = paginate :roles, :per_page => 25, :order => "position" @role_pages, @roles = paginate :roles, :per_page => 10, :order => "position"
render :action => "list", :layout => false if request.xhr? render :action => "list", :layout => false if request.xhr?
end end
def new def new
@role = Role.new(params[:role]) @role = Role.new(params[:role])
if request.post? if request.post?
@role.permissions = Permission.find(params[:permission_ids]) if params[:permission_ids] @role.permissions = Permission.find(params[:permission_ids]) if params[:permission_ids]
if @role.save if @role.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
@permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC') @permissions = Permission.find(:all, :conditions => ["is_public=?", false], :order => 'sort ASC')
end end
def edit def edit
@role = Role.find(params[:id]) @role = Role.find(params[:id])
if request.post? and @role.update_attributes(params[:role]) if request.post? and @role.update_attributes(params[:role])
@role.permissions = Permission.find(params[:permission_ids] || []) @role.permissions = Permission.find(params[:permission_ids] || [])
Permission.allowed_to_role_expired Permission.allowed_to_role_expired
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list' redirect_to :action => 'list'
@@ -56,60 +56,47 @@ class RolesController < ApplicationController
end end
def destroy def destroy
@role = Role.find(params[:id]) @role = Role.find(params[:id])
unless @role.members.empty? unless @role.members.empty?
flash[:notice] = 'Some members have this role. Can\'t delete it.' flash[:notice] = 'Some members have this role. Can\'t delete it.'
else else
@role.destroy @role.destroy
end end
redirect_to :action => 'list' redirect_to :action => 'list'
end end
def move def move
@role = Role.find(params[:id]) @role = Role.find(params[:id])
case params[:position] case params[:position]
when 'highest' when 'highest'
@role.move_to_top @role.move_to_top
when 'higher' when 'higher'
@role.move_higher @role.move_higher
when 'lower' when 'lower'
@role.move_lower @role.move_lower
when 'lowest' when 'lowest'
@role.move_to_bottom @role.move_to_bottom
end if params[:position] end if params[:position]
redirect_to :action => 'list' redirect_to :action => 'list'
end end
def workflow def workflow
@role = Role.find_by_id(params[:role_id]) @role = Role.find_by_id(params[:role_id])
@tracker = Tracker.find_by_id(params[:tracker_id]) @tracker = Tracker.find_by_id(params[:tracker_id])
if request.post? if request.post?
Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id])
(params[:issue_status] || []).each { |old, news| (params[:issue_status] || []).each { |old, news|
news.each { |new| news.each { |new|
@role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new)
} }
} }
if @role.save if @role.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
end end
end end
@roles = Role.find(:all, :order => 'position') @roles = Role.find(:all, :order => 'position')
@trackers = Tracker.find(:all, :order => 'position') @trackers = Tracker.find(:all, :order => 'position')
@statuses = IssueStatus.find(:all, :include => :workflows, :order => 'position') @statuses = IssueStatus.find(:all, :include => :workflows, :order => 'position')
end
def report
@roles = Role.find(:all, :order => 'position')
@permissions = Permission.find :all, :conditions => ["is_public=?", false], :order => 'sort'
if request.post?
@roles.each do |role|
role.permissions = Permission.find(params[:permission_ids] ? (params[:permission_ids][role.id.to_s] || []) : [] )
end
Permission.allowed_to_role_expired
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list'
end
end end
end end
-44
View File
@@ -1,44 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 SysController < ActionController::Base
wsdl_service_name 'Sys'
web_service_api SysApi
web_service_scaffold :invoke
before_invocation :check_enabled
def projects
Project.find(:all, :include => :repository)
end
def repository_created(project_id, url)
project = Project.find_by_id(project_id)
return 0 unless project && project.repository.nil?
logger.debug "Repository for #{project.name} created"
repository = Repository.new(:project => project, :url => url)
repository.root_url = url
repository.save
repository.id
end
protected
def check_enabled(name, args)
Setting.sys_api_enabled?
end
end
-80
View File
@@ -1,80 +0,0 @@
class TimelogController < ApplicationController
layout 'base'
before_filter :find_project
before_filter :authorize, :only => :edit
before_filter :check_project_privacy, :only => :details
helper :sort
include SortHelper
def details
sort_init 'spent_on', 'desc'
sort_update
@entries = (@issue ? @issue : @project).time_entries.find(:all, :include => [:activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :order => sort_clause)
@total_hours = @entries.inject(0) { |sum,entry| sum + entry.hours }
@owner_id = logged_in_user ? logged_in_user.id : 0
send_csv and return if 'csv' == params[:export]
render :action => 'details', :layout => false if request.xhr?
end
def edit
render_404 and return if @time_entry && @time_entry.user != logged_in_user
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => logged_in_user, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry]
if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'details', :project_id => @time_entry.project, :issue_id => @time_entry.issue
return
end
@activities = Enumeration::get_values('ACTI')
end
private
def find_project
if params[:id]
@time_entry = TimeEntry.find(params[:id])
@project = @time_entry.project
elsif params[:issue_id]
@issue = Issue.find(params[:issue_id])
@project = @issue.project
elsif params[:project_id]
@project = Project.find(params[:project_id])
else
render_404
return false
end
end
def send_csv
ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
export = StringIO.new
CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
# csv header fields
headers = [l(:field_spent_on),
l(:field_user),
l(:field_activity),
l(:field_issue),
l(:field_hours),
l(:field_comment)
]
csv << headers.collect {|c| ic.iconv(c) }
# csv lines
@entries.each do |entry|
fields = [l_date(entry.spent_on),
entry.user.name,
entry.activity.name,
(entry.issue ? entry.issue.id : nil),
entry.hours,
entry.comment
]
csv << fields.collect {|c| ic.iconv(c.to_s) }
end
end
export.rewind
send_data(export.read, :type => 'text/csv; header=present', :filename => 'export.csv')
end
end
+41 -48
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class TrackersController < ApplicationController class TrackersController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
def index def index
list list
@@ -28,23 +28,16 @@ class TrackersController < ApplicationController
verify :method => :post, :only => [ :destroy, :move ], :redirect_to => { :action => :list } verify :method => :post, :only => [ :destroy, :move ], :redirect_to => { :action => :list }
def list def list
@tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position'
render :action => "list", :layout => false if request.xhr? render :action => "list", :layout => false if request.xhr?
end end
def new def new
@tracker = Tracker.new(params[:tracker]) @tracker = Tracker.new(params[:tracker])
if request.post? and @tracker.save if request.post? and @tracker.save
# workflow copy
if params[:copy_workflow_from] && (copy_from = Tracker.find_by_id(params[:copy_workflow_from]))
copy_from.workflows.each do |w|
@tracker.workflows << w.clone
end
end
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'list' redirect_to :action => 'list'
end end
@trackers = Tracker.find :all
end end
def edit def edit
@@ -54,28 +47,28 @@ class TrackersController < ApplicationController
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
def move def move
@tracker = Tracker.find(params[:id]) @tracker = Tracker.find(params[:id])
case params[:position] case params[:position]
when 'highest' when 'highest'
@tracker.move_to_top @tracker.move_to_top
when 'higher' when 'higher'
@tracker.move_higher @tracker.move_higher
when 'lower' when 'lower'
@tracker.move_lower @tracker.move_lower
when 'lowest' when 'lowest'
@tracker.move_to_bottom @tracker.move_to_bottom
end if params[:position] end if params[:position]
redirect_to :action => 'list' redirect_to :action => 'list'
end end
def destroy def destroy
@tracker = Tracker.find(params[:id]) @tracker = Tracker.find(params[:id])
unless @tracker.issues.empty? unless @tracker.issues.empty?
flash[:notice] = "This tracker contains issues and can\'t be deleted." flash[:notice] = "This tracker contains issues and can\'t be deleted."
else else
@tracker.destroy @tracker.destroy
end end
redirect_to :action => 'list' redirect_to :action => 'list'
end end
+84 -90
View File
@@ -1,119 +1,113 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class UsersController < ApplicationController class UsersController < ApplicationController
layout 'base' layout 'base'
before_filter :require_admin before_filter :require_admin
helper :sort helper :sort
include SortHelper include SortHelper
helper :custom_fields helper :custom_fields
include CustomFieldsHelper include CustomFieldsHelper
def index def index
list list
render :action => 'list' unless request.xhr? render :action => 'list' unless request.xhr?
end end
def list def list
sort_init 'login', 'asc' sort_init 'login', 'asc'
sort_update sort_update
@user_count = User.count
@status = params[:status] ? params[:status].to_i : 1 @user_pages = Paginator.new self, @user_count,
conditions = nil 15,
conditions = ["status=?", @status] unless @status == 0 params['page']
@users = User.find :all,:order => sort_clause,
@user_count = User.count(:conditions => conditions) :limit => @user_pages.items_per_page,
@user_pages = Paginator.new self, @user_count, :offset => @user_pages.current.offset
15,
params['page']
@users = User.find :all,:order => sort_clause,
:conditions => conditions,
:limit => @user_pages.items_per_page,
:offset => @user_pages.current.offset
render :action => "list", :layout => false if request.xhr? render :action => "list", :layout => false if request.xhr?
end end
def add def add
if request.get? if request.get?
@user = User.new(:language => Setting.default_language) @user = User.new(:language => Setting.default_language)
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) } @custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user) }
else else
@user = User.new(params[:user]) @user = User.new(params[:user])
@user.admin = params[:user][:admin] || false @user.admin = params[:user][:admin] || false
@user.login = params[:user][:login] @user.login = params[:user][:login]
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless @user.auth_source_id
@custom_values = UserCustomField.find(:all).collect { |x| CustomValue.new(:custom_field => x, :customized => @user, :value => params["custom_fields"][x.id.to_s]) } @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 @user.custom_values = @custom_values
if @user.save if @user.save
flash[:notice] = l(:notice_successful_create) flash[:notice] = l(:notice_successful_create)
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
@auth_sources = AuthSource.find(:all) @auth_sources = AuthSource.find(:all)
end end
def edit def edit
@user = User.find(params[:id]) @user = User.find(params[:id])
if request.get? 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) } @custom_values = UserCustomField.find(:all).collect { |x| @user.custom_values.find_by_custom_field_id(x.id) || CustomValue.new(:custom_field => x) }
else else
@user.admin = params[:user][:admin] if params[:user][:admin] @user.admin = params[:user][:admin] if params[:user][:admin]
@user.login = params[:user][:login] if params[:user][:login] @user.login = params[:user][:login] if params[:user][:login]
@user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] unless params[:password].nil? or params[:password].empty? or @user.auth_source_id
if params[:custom_fields] 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]) } @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 @user.custom_values = @custom_values
end end
if @user.update_attributes(params[:user]) if @user.update_attributes(params[:user])
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list' redirect_to :action => 'list'
end end
end end
@auth_sources = AuthSource.find(:all) @auth_sources = AuthSource.find(:all)
@roles = Role.find(:all, :order => 'position') @roles = Role.find(:all, :order => 'position')
@projects = Project.find(:all) - @user.projects @projects = Project.find(:all) - @user.projects
@membership ||= Member.new @membership ||= Member.new
end end
def edit_membership def edit_membership
@user = User.find(params[:id]) @user = User.find(params[:id])
@membership = params[:membership_id] ? Member.find(params[:membership_id]) : Member.new(:user => @user) @membership = params[:membership_id] ? Member.find(params[:membership_id]) : Member.new(:user => @user)
@membership.attributes = params[:membership] @membership.attributes = params[:membership]
if request.post? and @membership.save if request.post? and @membership.save
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
end end
redirect_to :action => 'edit', :id => @user and return redirect_to :action => 'edit', :id => @user and return
end end
def destroy_membership def destroy_membership
@user = User.find(params[:id]) @user = User.find(params[:id])
if request.post? and Member.find(params[:membership_id]).destroy if request.post? and Member.find(params[:membership_id]).destroy
flash[:notice] = l(:notice_successful_update) flash[:notice] = l(:notice_successful_update)
end end
redirect_to :action => 'edit', :id => @user and return redirect_to :action => 'edit', :id => @user and return
end end
def destroy def destroy
User.find(params[:id]).destroy User.find(params[:id]).destroy
redirect_to :action => 'list'
rescue
flash[:notice] = "Unable to delete user"
redirect_to :action => 'list' redirect_to :action => 'list'
rescue end
flash[:notice] = "Unable to delete user"
redirect_to :action => 'list'
end
end end
+47 -47
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class VersionsController < ApplicationController class VersionsController < ApplicationController
layout 'base' layout 'base'
before_filter :find_project, :authorize before_filter :find_project, :authorize
def edit def edit
if request.post? and @version.update_attributes(params[:version]) if request.post? and @version.update_attributes(params[:version])
@@ -26,33 +26,33 @@ class VersionsController < ApplicationController
end end
end end
def destroy def destroy
@version.destroy @version.destroy
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
rescue rescue
flash[:notice] = "Unable to delete version" flash[:notice] = "Unable to delete version"
redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
end end
def download def download
@attachment = @version.attachments.find(params[:attachment_id]) @attachment = @version.attachments.find(params[:attachment_id])
@attachment.increment_download @attachment.increment_download
send_file @attachment.diskfile, :filename => @attachment.filename send_file @attachment.diskfile, :filename => @attachment.filename
rescue rescue
render_404 render_404
end end
def destroy_file def destroy_file
@version.attachments.find(params[:attachment_id]).destroy @version.attachments.find(params[:attachment_id]).destroy
flash[:notice] = l(:notice_successful_delete) flash[:notice] = l(:notice_successful_delete)
redirect_to :controller => 'projects', :action => 'list_files', :id => @project redirect_to :controller => 'projects', :action => 'list_files', :id => @project
end end
private private
def find_project def find_project
@version = Version.find(params[:id]) @version = Version.find(params[:id])
@project = @version.project @project = @version.project
rescue ActiveRecord::RecordNotFound rescue ActiveRecord::RecordNotFound
render_404 render_404
end end
end end
+23 -23
View File
@@ -1,25 +1,25 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class WelcomeController < ApplicationController class WelcomeController < ApplicationController
layout 'base' layout 'base'
def index def index
@news = News.latest logged_in_user @news = News.latest logged_in_user
@projects = Project.latest logged_in_user @projects = Project.latest logged_in_user
end end
end end
-112
View File
@@ -1,112 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 WikiController < ApplicationController
layout 'base'
before_filter :find_wiki, :check_project_privacy, :except => [:preview]
# display a page (in editing mode if it doesn't exist)
def index
page_title = params[:page]
@page = @wiki.find_or_new_page(page_title)
if @page.new_record?
edit
render :action => 'edit' and return
end
@content = @page.content_for_version(params[:version])
if params[:export] == 'html'
export = render_to_string :action => 'export', :layout => false
send_data(export, :type => 'text/html', :filename => "#{@page.title}.html")
return
elsif params[:export] == 'txt'
send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt")
return
end
render :action => 'show'
end
# edit an existing page or a new one
def edit
@page = @wiki.find_or_new_page(params[:page])
@page.content = WikiContent.new(:page => @page) if @page.new_record?
@content = @page.content_for_version(params[:version])
@content.text = "h1. #{@page.pretty_title}" if @content.text.blank?
# don't keep previous comment
@content.comment = nil
if request.post?
if @content.text == params[:content][:text]
# don't save if text wasn't changed
redirect_to :action => 'index', :id => @project, :page => @page.title
return
end
@content.text = params[:content][:text]
@content.comment = params[:content][:comment]
@content.author = logged_in_user
# if page is new @page.save will also save content, but not if page isn't a new record
if (@page.new_record? ? @page.save : @content.save)
redirect_to :action => 'index', :id => @project, :page => @page.title
end
end
end
# show page history
def history
@page = @wiki.find_page(params[:page])
# don't load text
@versions = @page.content.versions.find :all,
:select => "id, author_id, comment, updated_on, version",
:order => 'version DESC'
end
# display special pages
def special
page_title = params[:page].downcase
case page_title
# show pages index, sorted by title
when 'page_index'
# eager load information about last updates, without loading text
@pages = @wiki.pages.find :all, :select => "#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on",
:joins => "LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id",
:order => 'title'
# export wiki to a single html file
when 'export'
@pages = @wiki.pages.find :all, :order => 'title'
export = render_to_string :action => 'export_multiple', :layout => false
send_data(export, :type => 'text/html', :filename => "wiki.html")
return
else
# requested special page doesn't exist, redirect to default page
redirect_to :action => 'index', :id => @project, :page => nil and return
end
render :action => "special_#{page_title}"
end
def preview
@text = params[:content][:text]
render :partial => 'preview'
end
private
def find_wiki
@project = Project.find(params[:id])
@wiki = @project.wiki
rescue ActiveRecord::RecordNotFound
render_404
end
end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module AccountHelper module AccountHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module AdminHelper module AdminHelper
end end
+192 -240
View File
@@ -1,241 +1,193 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module ApplicationHelper module ApplicationHelper
# Return current logged in user or nil # Return current logged in user or nil
def loggedin? def loggedin?
@logged_in_user @logged_in_user
end end
# Return true if user is logged in and is admin, otherwise false # Return true if user is logged in and is admin, otherwise false
def admin_loggedin? def admin_loggedin?
@logged_in_user and @logged_in_user.admin? @logged_in_user and @logged_in_user.admin?
end end
# Return true if user is authorized for controller/action, otherwise false # Return true if user is authorized for controller/action, otherwise false
def authorize_for(controller, action) def authorize_for(controller, action)
# check if action is allowed on public projects # check if action is allowed on public projects
if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ] if @project.is_public? and Permission.allowed_to_public "%s/%s" % [ controller, action ]
return true return true
end end
# check if user is authorized # check if user is authorized
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) ) ) 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 return true
end end
return false return false
end end
# Display a link if user is authorized # Display a link if user is authorized
def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) 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]) link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller], options[:action])
end end
# Display a link to user's account page # Display a link to user's account page
def link_to_user(user) def link_to_user(user)
link_to user.display_name, :controller => 'account', :action => 'show', :id => user link_to user.display_name, :controller => 'account', :action => 'show', :id => user
end end
def link_to_issue(issue) def image_to_function(name, function, html_options = {})
link_to "#{issue.tracker.name} ##{issue.id}", :controller => "issues", :action => "show", :id => issue html_options.symbolize_keys!
end tag(:input, html_options.merge({
:type => "image", :src => image_path(name),
def toggle_link(name, id, options={}) :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
onclick = "Element.toggle('#{id}'); " }))
onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ") end
onclick << "return false;"
link_to(name, "#", :onclick => onclick) def format_date(date)
end l_date(date) if date
end
def image_to_function(name, function, html_options = {})
html_options.symbolize_keys! def format_time(time)
tag(:input, html_options.merge({ l_datetime(time) if time
:type => "image", :src => image_path(name), end
:onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};"
})) def day_name(day)
end l(:general_day_names).split(',')[day-1]
end
def format_date(date)
l_date(date) if date def month_name(month)
end l(:actionview_datehelper_select_month_names).split(',')[month-1]
end
def format_time(time)
l_datetime((time.is_a? String) ? time.to_time : time) if time def pagination_links_full(paginator, options={}, html_options={})
end html = ''
html << link_to_remote(('&#171; ' + l(:label_previous)),
def day_name(day) {:update => "content", :url => { :page => paginator.current.previous }},
l(:general_day_names).split(',')[day-1] {:href => url_for(:action => 'list', :params => params.merge({:page => paginator.current.previous}))}) + ' ' if paginator.current.previous
end
html << (pagination_links_each(paginator, options) do |n|
def month_name(month) link_to_remote(n.to_s,
l(:actionview_datehelper_select_month_names).split(',')[month-1] {:url => {:action => 'list', :params => params.merge({:page => n})}, :update => 'content'},
end {:href => url_for(:action => 'list', :params => params.merge({:page => n}))})
end || '')
def pagination_links_full(paginator, options={}, html_options={})
html = '' html << ' ' + link_to_remote((l(:label_next) + ' &#187;'),
html << link_to_remote(('&#171; ' + l(:label_previous)), {:update => "content", :url => { :page => paginator.current.next }},
{:update => "content", :url => options.merge(:page => paginator.current.previous)}, {:href => url_for(:action => 'list', :params => params.merge({:page => paginator.current.next}))}) if paginator.current.next
{:href => url_for(:params => options.merge(:page => paginator.current.previous))}) + ' ' if paginator.current.previous html
end
html << (pagination_links_each(paginator, options) do |n|
link_to_remote(n.to_s, def textilizable(text)
{:url => {:params => options.merge(:page => n)}, :update => 'content'}, (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") ? RedCloth.new(h(text)).to_html : simple_format(auto_link(h(text)))
{:href => url_for(:params => options.merge(:page => n))}) end
end || '')
def error_messages_for(object_name, options = {})
html << ' ' + link_to_remote((l(:label_next) + ' &#187;'), options = options.symbolize_keys
{:update => "content", :url => options.merge(:page => paginator.current.next)}, object = instance_variable_get("@#{object_name}")
{:href => url_for(:params => options.merge(:page => paginator.current.next))}) if paginator.current.next if object && !object.errors.empty?
html # build full_messages here with controller current language
end full_messages = []
object.errors.each do |attr, msg|
# textilize text according to system settings and RedCloth availability next if msg.nil?
def textilizable(text, options = {}) if attr == "base"
# different methods for formatting wiki links full_messages << l(msg)
case options[:wiki_links] else
when :local full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values"
# used for local links to html files end
format_wiki_link = Proc.new {|title| "#{title}.html" } end
when :anchor # retrieve custom values error messages
# used for single-file wiki export if object.errors[:custom_values]
format_wiki_link = Proc.new {|title| "##{title}" } object.custom_values.each do |v|
else v.errors.each do |attr, msg|
if @project next if msg.nil?
format_wiki_link = Proc.new {|title| url_for :controller => 'wiki', :action => 'index', :id => @project, :page => title } full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
else end
format_wiki_link = Proc.new {|title| title } end
end end
end content_tag("div",
content_tag(
# turn wiki links into textile links: options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :"
# example: ) +
# [[link]] -> "link":link content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
# [[link|title]] -> "title":link "id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
text = text.gsub(/\[\[([^\]\|]+)(\|([^\]\|]+))?\]\]/) {|m| "\"#{$3 || $1}\":" + format_wiki_link.call(Wiki.titleize($1)) } )
else
# turn issue ids to textile links ""
# example: end
# #52 -> "#52":/issues/show/52 end
text = text.gsub(/#(\d+)(?=\b)/) {|m| "\"##{$1}\":" + url_for(:controller => 'issues', :action => 'show', :id => $1) }
def lang_options_for_select(blank=true)
# turn revision ids to textile links (@project needed) (blank ? [["(auto)", ""]] : []) +
# example: (GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]}
# r52 -> "r52":/repositories/revision/6?rev=52 (@project.id is 6) end
text = text.gsub(/(?=\b)r(\d+)(?=\b)/) {|m| "\"r#{$1}\":" + url_for(:controller => 'repositories', :action => 'revision', :id => @project.id, :rev => $1) } if @project
def label_tag_for(name, option_tags = nil, options = {})
# finally textilize text label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
@do_textilize ||= (Setting.text_formatting == 'textile') && (ActionView::Helpers::TextHelper.method_defined? "textilize") content_tag("label", label_text)
text = @do_textilize ? auto_link(RedCloth.new(text).to_html) : simple_format(auto_link(h(text))) end
end
def labelled_tabular_form_for(name, object, options, &proc)
def error_messages_for(object_name, options = {}) options[:html] ||= {}
options = options.symbolize_keys options[:html].store :class, "tabular"
object = instance_variable_get("@#{object_name}") form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
if object && !object.errors.empty? end
# build full_messages here with controller current language
full_messages = [] def check_all_links(form_name)
object.errors.each do |attr, msg| link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
next if msg.nil? " | " +
msg = msg.first if msg.is_a? Array link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
if attr == "base" end
full_messages << l(msg)
else def calendar_for(field_id)
full_messages << "&#171; " + (l_has_string?("field_" + attr) ? l("field_" + attr) : object.class.human_attribute_name(attr)) + " &#187; " + l(msg) unless attr == "custom_values" image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
end javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
end end
# retrieve custom values error messages
if object.errors[:custom_values]
object.custom_values.each do |v|
v.errors.each do |attr, msg|
next if msg.nil?
msg = msg.first if msg.is_a? Array
full_messages << "&#171; " + v.custom_field.name + " &#187; " + l(msg)
end
end
end
content_tag("div",
content_tag(
options[:header_tag] || "h2", lwr(:gui_validation_error, full_messages.length) + " :"
) +
content_tag("ul", full_messages.collect { |msg| content_tag("li", msg) }),
"id" => options[:id] || "errorExplanation", "class" => options[:class] || "errorExplanation"
)
else
""
end
end
def lang_options_for_select(blank=true)
(blank ? [["(auto)", ""]] : []) +
(GLoc.valid_languages.sort {|x,y| x.to_s <=> y.to_s }).collect {|lang| [ l_lang_name(lang.to_s, lang), lang.to_s]}
end
def label_tag_for(name, option_tags = nil, options = {})
label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
content_tag("label", label_text)
end
def labelled_tabular_form_for(name, object, options, &proc)
options[:html] ||= {}
options[:html].store :class, "tabular"
form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
end
def check_all_links(form_name)
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
" | " +
link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
end
def calendar_for(field_id)
image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
end
end end
class TabularFormBuilder < ActionView::Helpers::FormBuilder class TabularFormBuilder < ActionView::Helpers::FormBuilder
include GLoc include GLoc
def initialize(object_name, object, template, options, proc) def initialize(object_name, object, template, options, proc)
set_language_if_valid options.delete(:lang) set_language_if_valid options.delete(:lang)
@object_name, @object, @template, @options, @proc = object_name, object, template, options, proc @object_name, @object, @template, @options, @proc = object_name, object, template, options, proc
end end
(field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector| (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector|
src = <<-END_SRC src = <<-END_SRC
def #{selector}(field, options = {}) def #{selector}(field, options = {})
return super if options.delete :no_label return super if options.delete :no_label
label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
label = @template.content_tag("label", label_text, label = @template.content_tag("label", label_text,
:class => (@object && @object.errors[field] ? "error" : nil), :class => (@object && @object.errors[field] ? "error" : nil),
:for => (@object_name.to_s + "_" + field.to_s)) :for => (@object_name.to_s + "_" + field.to_s))
label + super label + super
end end
END_SRC END_SRC
class_eval src, __FILE__, __LINE__ class_eval src, __FILE__, __LINE__
end end
def select(field, choices, options = {}, html_options = {}) def select(field, choices, options = {}, html_options = {})
label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "")
label = @template.content_tag("label", label_text, label = @template.content_tag("label", label_text,
:class => (@object && @object.errors[field] ? "error" : nil), :class => (@object && @object.errors[field] ? "error" : nil),
:for => (@object_name.to_s + "_" + field.to_s)) :for => (@object_name.to_s + "_" + field.to_s))
label + super label + super
end end
end end
+75 -75
View File
@@ -1,77 +1,77 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module CustomFieldsHelper module CustomFieldsHelper
# Return custom field html tag corresponding to its format # Return custom field html tag corresponding to its format
def custom_field_tag(custom_value) def custom_field_tag(custom_value)
custom_field = custom_value.custom_field custom_field = custom_value.custom_field
field_name = "custom_fields[#{custom_field.id}]" field_name = "custom_fields[#{custom_field.id}]"
field_id = "custom_fields_#{custom_field.id}" field_id = "custom_fields_#{custom_field.id}"
case custom_field.field_format case custom_field.field_format
when "string", "int" when "string", "int"
text_field 'custom_value', 'value', :name => field_name, :id => field_id text_field 'custom_value', 'value', :name => field_name, :id => field_id
when "date" when "date"
text_field('custom_value', 'value', :name => field_name, :id => field_id, :size => 10) + text_field('custom_value', 'value', :name => field_name, :id => field_id, :size => 10) +
calendar_for(field_id) calendar_for(field_id)
when "text" when "text"
text_area 'custom_value', 'value', :name => field_name, :id => field_id, :cols => 60, :rows => 3 text_area 'custom_value', 'value', :name => field_name, :id => field_id, :cols => 60, :rows => 3
when "bool" when "bool"
check_box 'custom_value', 'value', :name => field_name, :id => field_id check_box 'custom_value', 'value', :name => field_name, :id => field_id
when "list" when "list"
select 'custom_value', 'value', custom_field.possible_values, { :include_blank => true }, :name => field_name, :id => field_id select 'custom_value', 'value', custom_field.possible_values, { :include_blank => true }, :name => field_name, :id => field_id
end end
end end
# Return custom field label tag # Return custom field label tag
def custom_field_label_tag(custom_value) def custom_field_label_tag(custom_value)
content_tag "label", custom_value.custom_field.name + content_tag "label", custom_value.custom_field.name +
(custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""), (custom_value.custom_field.is_required? ? " <span class=\"required\">*</span>" : ""),
:for => "custom_fields_#{custom_value.custom_field.id}", :for => "custom_fields_#{custom_value.custom_field.id}",
:class => (custom_value.errors.empty? ? nil : "error" ) :class => (custom_value.errors.empty? ? nil : "error" )
end end
# Return custom field tag with its label tag # Return custom field tag with its label tag
def custom_field_tag_with_label(custom_value) def custom_field_tag_with_label(custom_value)
custom_field_label_tag(custom_value) + custom_field_tag(custom_value) custom_field_label_tag(custom_value) + custom_field_tag(custom_value)
end end
# Return a string used to display a custom value # Return a string used to display a custom value
def show_value(custom_value) def show_value(custom_value)
return "" unless custom_value return "" unless custom_value
format_value(custom_value.value, custom_value.custom_field.field_format) format_value(custom_value.value, custom_value.custom_field.field_format)
end end
# Return a string used to display a custom value # Return a string used to display a custom value
def format_value(value, field_format) def format_value(value, field_format)
return "" unless value && !value.empty? return "" unless value && !value.empty?
case field_format case field_format
when "date" when "date"
begin; l_date(value.to_date); rescue; value end begin; l_date(value.to_date); rescue; value end
when "bool" when "bool"
l_YesNo(value == "1") l_YesNo(value == "1")
else else
value value
end end
end end
# Return an array of custom field formats which can be used in select_tag # Return an array of custom field formats which can be used in select_tag
def custom_field_formats_for_select def custom_field_formats_for_select
CustomField::FIELD_FORMATS.sort {|a,b| a[1][:order]<=>b[1][:order]}.collect { |k| [ l(k[1][:name]), k[0] ] } CustomField::FIELD_FORMATS.sort {|a,b| a[1][:order]<=>b[1][:order]}.collect { |k| [ l(k[1][:name]), k[0] ] }
end end
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module DocumentsHelper module DocumentsHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module EnumerationsHelper module EnumerationsHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module HelpHelper module HelpHelper
end end
+52 -74
View File
@@ -1,75 +1,53 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'iconv' require 'iconv'
require 'rfpdf/chinese'
module IfpdfHelper
module IfpdfHelper
class IFPDF < FPDF
class IFPDF < FPDF
include GLoc attr_accessor :footer_date
attr_accessor :footer_date
def initialize
def initialize(lang) super
super() SetCreator("redMine #{Redmine::VERSION}")
set_language_if_valid lang end
case current_language
when :ja def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
extend(PDF_Japanese) @ic ||= Iconv.new('ISO-8859-1', 'UTF-8')
AddSJISFont() txt = begin
@font_for_content = 'SJIS' @ic.iconv(txt)
@font_for_footer = 'SJIS' rescue
when :zh txt
extend(PDF_Chinese) end
AddBig5Font() super w,h,txt,border,ln,align,fill,link
@font_for_content = 'Big5' end
@font_for_footer = 'Big5'
else def Footer
@font_for_content = 'Arial' SetFont('Helvetica', 'I', 8)
@font_for_footer = 'Helvetica' SetY(-15)
end SetX(15)
SetCreator("redMine #{Redmine::VERSION}") Cell(0, 5, @footer_date, 0, 0, 'L')
SetFont(@font_for_content) SetY(-15)
end SetX(-30)
Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
def SetFontStyle(style, size) end
SetFont(@font_for_content, style, size)
end
def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='')
@ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8')
txt = begin
@ic.iconv(txt)
rescue
txt
end
super w,h,txt,border,ln,align,fill,link
end
def Footer
SetFont(@font_for_footer, 'I', 8)
SetY(-15)
SetX(15)
Cell(0, 5, @footer_date, 0, 0, 'L')
SetY(-15)
SetX(-30)
Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
end
end end
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module IssueCategoriesHelper module IssueCategoriesHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module IssueStatusesHelper module IssueStatusesHelper
end end
+72 -84
View File
@@ -1,86 +1,74 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module IssuesHelper module IssuesHelper
def show_detail(detail, no_html=false) def show_detail(detail, no_html=false)
case detail.property case detail.property
when 'attr' when 'attr'
label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym) label = l(("field_" + detail.prop_key.to_s.gsub(/\_id$/, "")).to_sym)
case detail.prop_key case detail.prop_key
when 'due_date', 'start_date' when 'due_date', 'start_date'
value = format_date(detail.value.to_date) if detail.value value = format_date(detail.value.to_date) if detail.value
old_value = format_date(detail.old_value.to_date) if detail.old_value old_value = format_date(detail.old_value.to_date) if detail.old_value
when 'status_id' when 'status_id'
s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value s = IssueStatus.find_by_id(detail.value) and value = s.name if detail.value
s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value s = IssueStatus.find_by_id(detail.old_value) and old_value = s.name if detail.old_value
when 'assigned_to_id' when 'assigned_to_id'
u = User.find_by_id(detail.value) and value = u.name if detail.value u = User.find_by_id(detail.value) and value = u.name if detail.value
u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value u = User.find_by_id(detail.old_value) and old_value = u.name if detail.old_value
when 'priority_id' when 'priority_id'
e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value e = Enumeration.find_by_id(detail.value) and value = e.name if detail.value
e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value e = Enumeration.find_by_id(detail.old_value) and old_value = e.name if detail.old_value
when 'category_id' when 'category_id'
c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value c = IssueCategory.find_by_id(detail.value) and value = c.name if detail.value
c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value c = IssueCategory.find_by_id(detail.old_value) and old_value = c.name if detail.old_value
when 'fixed_version_id' when 'fixed_version_id'
v = Version.find_by_id(detail.value) and value = v.name if detail.value v = Version.find_by_id(detail.value) and value = v.name if detail.value
v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value v = Version.find_by_id(detail.old_value) and old_value = v.name if detail.old_value
end end
when 'cf' when 'cf'
custom_field = CustomField.find_by_id(detail.prop_key) custom_field = CustomField.find_by_id(detail.prop_key)
if custom_field if custom_field
label = custom_field.name label = custom_field.name
value = format_value(detail.value, custom_field.field_format) if detail.value value = format_value(detail.value, custom_field.field_format) if detail.value
old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
end end
when 'attachment' end
label = l(:label_attachment)
end label ||= detail.prop_key
value ||= detail.value
label ||= detail.prop_key old_value ||= detail.old_value
value ||= detail.value
old_value ||= detail.old_value unless no_html
label = content_tag('strong', label)
unless no_html old_value = content_tag("i", h(old_value)) if detail.old_value
label = content_tag('strong', label) old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
old_value = content_tag("i", h(old_value)) if detail.old_value value = content_tag("i", h(value)) if value
old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?) end
value = content_tag("i", h(value)) if value
end if detail.value and !detail.value.to_s.empty?
if old_value
if detail.value and !detail.value.to_s.empty? label + " " + l(:text_journal_changed, old_value, value)
case detail.property else
when 'attr', 'cf' label + " " + l(:text_journal_set_to, value)
if old_value end
label + " " + l(:text_journal_changed, old_value, value) else
else label + " " + l(:text_journal_deleted) + " (#{old_value})"
label + " " + l(:text_journal_set_to, value) end
end
when 'attachment'
"#{label} #{value} #{l(:label_added)}"
end
else
case detail.property
when 'attr', 'cf'
label + " " + l(:text_journal_deleted) + " (#{old_value})"
when 'attachment'
"#{label} #{old_value} #{l(:label_deleted)}"
end
end
end end
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module MembersHelper module MembersHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module NewsHelper module NewsHelper
end end
+17 -27
View File
@@ -1,29 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module ProjectsHelper module ProjectsHelper
def highlight_tokens(text, tokens)
return text unless tokens && !tokens.empty?
regexp = Regexp.new "(#{tokens.join('|')})", Regexp::IGNORECASE
result = ''
text.split(regexp).each_with_index do |words, i|
result << (i.even? ? (words.length > 100 ? "#{words[0..44]} ... #{words[-45..-1]}" : words) : content_tag('span', words, :class => 'highlight'))
end
result
end
end end
+30 -30
View File
@@ -1,32 +1,32 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module ReportsHelper module ReportsHelper
def aggregate(data, criteria) def aggregate(data, criteria)
a = 0 a = 0
data.each { |row| data.each { |row|
match = 1 match = 1
criteria.each { |k, v| criteria.each { |k, v|
match = 0 unless row[k].to_s == v.to_s match = 0 unless row[k].to_s == v.to_s
} unless criteria.nil? } unless criteria.nil?
a = a + row["total"].to_i if match == 1 a = a + row["total"].to_i if match == 1
} unless data.nil? } unless data.nil?
a a
end end
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module RolesHelper module RolesHelper
end end
+3 -5
View File
@@ -107,12 +107,10 @@ module SortHelper
order = 'desc' # changed for desc order by default order = 'desc' # changed for desc order by default
end end
caption = titleize(Inflector::humanize(column)) unless caption caption = titleize(Inflector::humanize(column)) unless caption
params = {:params => {:sort_key => column, :sort_order => order}}
url = {:sort_key => column, :sort_order => order, :issue_id => params[:issue_id], :project_id => params[:project_id]}
link_to_remote(caption, link_to_remote(caption,
{:update => "content", :url => url}, {:update => "content", :url => { :sort_key => column, :sort_order => order}},
{:href => url_for(url)}) + {:href => url_for(:params => { :sort_key => column, :sort_order => order})}) +
(icon ? nbsp(2) + image_tag(icon) : '') (icon ? nbsp(2) + image_tag(icon) : '')
end end
-2
View File
@@ -1,2 +0,0 @@
module TimelogHelper
end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module TrackersHelper module TrackersHelper
end end
+17 -23
View File
@@ -1,25 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module UsersHelper module UsersHelper
def status_options_for_select(selected)
options_for_select([[l(:label_all), "*"],
[l(:status_active), 1],
[l(:status_registered), 2],
[l(:status_locked), 3]], selected)
end
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module VersionsHelper module VersionsHelper
end end
+17 -17
View File
@@ -1,19 +1,19 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
module WelcomeHelper module WelcomeHelper
end end
-19
View File
@@ -1,19 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 WikiHelper
end
+90 -90
View File
@@ -1,92 +1,92 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require "digest/md5" require "digest/md5"
class Attachment < ActiveRecord::Base class Attachment < ActiveRecord::Base
belongs_to :container, :polymorphic => true belongs_to :container, :polymorphic => true
belongs_to :author, :class_name => "User", :foreign_key => "author_id" belongs_to :author, :class_name => "User", :foreign_key => "author_id"
validates_presence_of :container, :filename validates_presence_of :container, :filename
cattr_accessor :storage_path cattr_accessor :storage_path
@@storage_path = "#{RAILS_ROOT}/files" @@storage_path = "#{RAILS_ROOT}/files"
def validate def validate
errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
end end
def file=(incomming_file) def file=(incomming_file)
unless incomming_file.nil? unless incomming_file.nil?
@temp_file = incomming_file @temp_file = incomming_file
if @temp_file.size > 0 if @temp_file.size > 0
self.filename = sanitize_filename(@temp_file.original_filename) self.filename = sanitize_filename(@temp_file.original_filename)
self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
self.content_type = @temp_file.content_type self.content_type = @temp_file.content_type
self.filesize = @temp_file.size self.filesize = @temp_file.size
end end
end end
end end
def file def file
nil nil
end end
# Copy temp file to its final location # Copy temp file to its final location
def before_save def before_save
if @temp_file && (@temp_file.size > 0) if @temp_file && (@temp_file.size > 0)
logger.debug("saving '#{self.diskfile}'") logger.debug("saving '#{self.diskfile}'")
File.open(diskfile, "wb") do |f| File.open(diskfile, "wb") do |f|
f.write(@temp_file.read) f.write(@temp_file.read)
end end
self.digest = Digest::MD5.hexdigest(File.read(diskfile)) self.digest = Digest::MD5.hexdigest(File.read(diskfile))
end end
end end
# Deletes file on the disk # Deletes file on the disk
def after_destroy def after_destroy
if self.filename? if self.filename?
File.delete(diskfile) if File.exist?(diskfile) File.delete(diskfile) if File.exist?(diskfile)
end end
end end
# Returns file's location on disk # Returns file's location on disk
def diskfile def diskfile
"#{@@storage_path}/#{self.disk_filename}" "#{@@storage_path}/#{self.disk_filename}"
end end
def increment_download def increment_download
increment!(:downloads) increment!(:downloads)
end end
# returns last created projects # returns last created projects
def self.most_downloaded def self.most_downloaded
find(:all, :limit => 5, :order => "downloads DESC") find(:all, :limit => 5, :order => "downloads DESC")
end end
private private
def sanitize_filename(value) def sanitize_filename(value)
# get only the filename, not the whole path # get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '') just_filename = value.gsub(/^.*(\\|\/)/, '')
# NOTE: File.basename doesn't work right with Windows paths on Unix # NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/')) # INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
# Finally, replace all non alphanumeric, underscore or periods with underscore # Finally, replace all non alphanumeric, underscore or periods with underscore
@filename = just_filename.gsub(/[^\w\.\-]/,'_') @filename = just_filename.gsub(/[^\w\.\-]/,'_')
end end
end end
+77 -77
View File
@@ -1,79 +1,79 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'net/ldap' require 'net/ldap'
require 'iconv' require 'iconv'
class AuthSourceLdap < AuthSource class AuthSourceLdap < AuthSource
validates_presence_of :host, :port, :attr_login validates_presence_of :host, :port, :attr_login
def after_initialize def after_initialize
self.port = 389 if self.port == 0 self.port = 389 if self.port == 0
end end
def authenticate(login, password) def authenticate(login, password)
attrs = [] attrs = []
# get user's DN # get user's DN
ldap_con = initialize_ldap_con(self.account, self.account_password) ldap_con = initialize_ldap_con(self.account, self.account_password)
login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
dn = String.new dn = String.new
ldap_con.search( :base => self.base_dn, ldap_con.search( :base => self.base_dn,
:filter => object_filter & login_filter, :filter => object_filter & login_filter,
:attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry| :attributes=> ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail]) do |entry|
dn = entry.dn dn = entry.dn
attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), attrs = [:firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname),
:lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname),
:mail => AuthSourceLdap.get_attr(entry, self.attr_mail), :mail => AuthSourceLdap.get_attr(entry, self.attr_mail),
:auth_source_id => self.id ] :auth_source_id => self.id ]
end end
return nil if dn.empty? return nil if dn.empty?
logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug? logger.debug "DN found for #{login}: #{dn}" if logger && logger.debug?
# authenticate user # authenticate user
ldap_con = initialize_ldap_con(dn, password) ldap_con = initialize_ldap_con(dn, password)
return nil unless ldap_con.bind return nil unless ldap_con.bind
# return user's attributes # return user's attributes
logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? logger.debug "Authentication successful for '#{login}'" if logger && logger.debug?
attrs attrs
rescue Net::LDAP::LdapError => text rescue Net::LDAP::LdapError => text
raise "LdapError: " + text raise "LdapError: " + text
end end
# test the connection to the LDAP # test the connection to the LDAP
def test_connection def test_connection
ldap_con = initialize_ldap_con(self.account, self.account_password) ldap_con = initialize_ldap_con(self.account, self.account_password)
ldap_con.open { } ldap_con.open { }
rescue Net::LDAP::LdapError => text rescue Net::LDAP::LdapError => text
raise "LdapError: " + text raise "LdapError: " + text
end end
def auth_method_name def auth_method_name
"LDAP" "LDAP"
end end
private private
def initialize_ldap_con(ldap_user, ldap_password) def initialize_ldap_con(ldap_user, ldap_password)
Net::LDAP.new( {:host => self.host, Net::LDAP.new( {:host => self.host,
:port => self.port, :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) }} :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 end
def self.get_attr(entry, attr_name) def self.get_attr(entry, attr_name)
entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name]
end end
end end
-22
View File
@@ -1,22 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 Change < ActiveRecord::Base
belongs_to :changeset
validates_presence_of :changeset_id, :action, :path
end
-30
View File
@@ -1,30 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 Changeset < ActiveRecord::Base
belongs_to :repository
has_many :changes, :dependent => :delete_all
validates_presence_of :repository_id, :revision, :committed_on, :commit_date
validates_numericality_of :revision, :only_integer => true
validates_uniqueness_of :revision, :scope => :repository_id
def committed_on=(date)
self.commit_date = date
super
end
end
+59 -59
View File
@@ -1,60 +1,60 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomField < ActiveRecord::Base class CustomField < ActiveRecord::Base
has_many :custom_values, :dependent => :delete_all has_many :custom_values, :dependent => :delete_all
serialize :possible_values serialize :possible_values
FIELD_FORMATS = { "string" => { :name => :label_string, :order => 1 }, FIELD_FORMATS = { "string" => { :name => :label_string, :order => 1 },
"text" => { :name => :label_text, :order => 2 }, "text" => { :name => :label_text, :order => 2 },
"int" => { :name => :label_integer, :order => 3 }, "int" => { :name => :label_integer, :order => 3 },
"list" => { :name => :label_list, :order => 4 }, "list" => { :name => :label_list, :order => 4 },
"date" => { :name => :label_date, :order => 5 }, "date" => { :name => :label_date, :order => 5 },
"bool" => { :name => :label_boolean, :order => 6 } "bool" => { :name => :label_boolean, :order => 6 }
}.freeze }.freeze
validates_presence_of :name, :field_format validates_presence_of :name, :field_format
validates_uniqueness_of :name validates_uniqueness_of :name
validates_format_of :name, :with => /^[\w\s\'\-]*$/i validates_format_of :name, :with => /^[\w\s\'\-]*$/i
validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys validates_inclusion_of :field_format, :in => FIELD_FORMATS.keys
def initialize(attributes = nil) def initialize(attributes = nil)
super super
self.possible_values ||= [] self.possible_values ||= []
end
def before_validation
# remove empty values
self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
end
def validate
if self.field_format == "list"
errors.add(:possible_values, :activerecord_error_blank) if self.possible_values.nil? || self.possible_values.empty?
errors.add(:possible_values, :activerecord_error_invalid) unless self.possible_values.is_a? Array
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
end
def before_validation
# remove empty values
self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact
end
def validate
if self.field_format == "list"
errors.add(:possible_values, :activerecord_error_blank) if self.possible_values.nil? || self.possible_values.empty?
errors.add(:possible_values, :activerecord_error_invalid) unless self.possible_values.is_a? Array
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
+36 -36
View File
@@ -1,38 +1,38 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class CustomValue < ActiveRecord::Base class CustomValue < ActiveRecord::Base
belongs_to :custom_field belongs_to :custom_field
belongs_to :customized, :polymorphic => true belongs_to :customized, :polymorphic => true
protected protected
def validate def validate
errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty? errors.add(:value, :activerecord_error_blank) and return if custom_field.is_required? and value.empty?
errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp) errors.add(:value, :activerecord_error_invalid) unless custom_field.regexp.empty? or value =~ Regexp.new(custom_field.regexp)
errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0 errors.add(:value, :activerecord_error_too_short) if custom_field.min_length > 0 and value.length < custom_field.min_length and value.length > 0
errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length errors.add(:value, :activerecord_error_too_long) if custom_field.max_length > 0 and value.length > custom_field.max_length
case custom_field.field_format case custom_field.field_format
when "int" when "int"
errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/ errors.add(:value, :activerecord_error_not_a_number) unless value =~ /^[0-9]*$/
when "date" when "date"
errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty? errors.add(:value, :activerecord_error_not_a_date) unless value =~ /^\d{4}-\d{2}-\d{2}$/ or value.empty?
when "list" when "list"
errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.include? value or value.empty? errors.add(:value, :activerecord_error_inclusion) unless custom_field.possible_values.include? value or value.empty?
end end
end end
end end
+22 -22
View File
@@ -1,24 +1,24 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Document < ActiveRecord::Base class Document < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id"
has_many :attachments, :as => :container, :dependent => :destroy has_many :attachments, :as => :container, :dependent => :destroy
validates_presence_of :project, :title, :category validates_presence_of :project, :title, :category
end end
+45 -48
View File
@@ -1,50 +1,47 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Enumeration < ActiveRecord::Base class Enumeration < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
validates_presence_of :opt, :name validates_presence_of :opt, :name
validates_uniqueness_of :name, :scope => [:opt] validates_uniqueness_of :name, :scope => [:opt]
validates_format_of :name, :with => /^[\w\s\'\-]*$/i validates_format_of :name, :with => /^[\w\s\'\-]*$/i
OPTIONS = { OPTIONS = {
"IPRI" => :enumeration_issue_priorities, "IPRI" => :enumeration_issue_priorities,
"DCAT" => :enumeration_doc_categories, "DCAT" => :enumeration_doc_categories
"ACTI" => :enumeration_activities }.freeze
}.freeze
def self.get_values(option)
def self.get_values(option) find(:all, :conditions => ['opt=?', option])
find(:all, :conditions => ['opt=?', option]) end
end
def option_name
def option_name OPTIONS[self.opt]
OPTIONS[self.opt] end
end
private
private def check_integrity
def check_integrity case self.opt
case self.opt when "IPRI"
when "IPRI" raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id])
raise "Can't delete enumeration" if Issue.find(:first, :conditions => ["priority_id=?", self.id]) when "DCAT"
when "DCAT" raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id])
raise "Can't delete enumeration" if Document.find(:first, :conditions => ["category_id=?", self.id]) end
when "ACTI"
raise "Can't delete enumeration" if TimeEntry.find(:first, :conditions => ["activity_id=?", self.id])
end
end end
end end
+101 -105
View File
@@ -1,106 +1,102 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Issue < ActiveRecord::Base class Issue < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :tracker belongs_to :tracker
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id' belongs_to :assigned_to, :class_name => 'User', :foreign_key => 'assigned_to_id'
belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id'
belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id' belongs_to :priority, :class_name => 'Enumeration', :foreign_key => 'priority_id'
belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id'
has_many :journals, :as => :journalized, :dependent => :destroy has_many :journals, :as => :journalized, :dependent => :destroy
has_many :attachments, :as => :container, :dependent => :destroy has_many :attachments, :as => :container, :dependent => :destroy
has_many :time_entries
has_many :custom_values, :dependent => :delete_all, :as => :customized has_many :custom_values, :dependent => :delete_all, :as => :customized
has_many :custom_fields, :through => :custom_values has_many :custom_fields, :through => :custom_values
validates_presence_of :subject, :description, :priority, :tracker, :author, :status validates_presence_of :subject, :description, :priority, :tracker, :author, :status
validates_inclusion_of :done_ratio, :in => 0..100 validates_inclusion_of :done_ratio, :in => 0..100
validates_associated :custom_values, :on => :update validates_associated :custom_values, :on => :update
# set default status for new issues # set default status for new issues
def before_validation def before_validation
self.status = IssueStatus.default if status.nil? self.status = IssueStatus.default if new_record?
end end
def validate def validate
if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty? if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
errors.add :due_date, :activerecord_error_not_a_date errors.add :due_date, :activerecord_error_not_a_date
end end
if self.due_date and self.start_date and self.due_date < self.start_date if self.due_date and self.start_date and self.due_date < self.start_date
errors.add :due_date, :activerecord_error_greater_than_start_date errors.add :due_date, :activerecord_error_greater_than_start_date
end end
end end
#def before_create #def before_create
# build_history # build_history
#end #end
def before_save def before_save
if @current_journal if @current_journal
# attributes changes # attributes changes
(Issue.column_names - %w(id description)).each {|c| (Issue.column_names - %w(id description)).each {|c|
@current_journal.details << JournalDetail.new(:property => 'attr', @current_journal.details << JournalDetail.new(:property => 'attr',
:prop_key => c, :prop_key => c,
:old_value => @issue_before_change.send(c), :old_value => @issue_before_change.send(c),
:value => send(c)) unless send(c)==@issue_before_change.send(c) :value => send(c)) unless send(c)==@issue_before_change.send(c)
} }
# custom fields changes # custom fields changes
custom_values.each {|c| custom_values.each {|c|
@current_journal.details << JournalDetail.new(:property => 'cf', @current_journal.details << JournalDetail.new(:property => 'cf',
:prop_key => c.custom_field_id, :prop_key => c.custom_field_id,
:old_value => @custom_values_before_change[c.custom_field_id], :old_value => @custom_values_before_change[c.custom_field_id],
:value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value :value => c.value) unless @custom_values_before_change[c.custom_field_id]==c.value
} }
@current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty? @current_journal.save unless @current_journal.details.empty? and @current_journal.notes.empty?
end end
end end
def long_id def long_id
"%05d" % self.id "%05d" % self.id
end end
def custom_value_for(custom_field) def custom_value_for(custom_field)
self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id } self.custom_values.each {|v| return v if v.custom_field_id == custom_field.id }
return nil return nil
end end
def init_journal(user, notes = "") def init_journal(user, notes = "")
@current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes)
@issue_before_change = self.clone @issue_before_change = self.clone
@custom_values_before_change = {} @custom_values_before_change = {}
self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value }
@current_journal @current_journal
end end
def spent_hours private
@spent_hours ||= time_entries.sum(:hours) || 0 # Creates an history for the issue
end #def build_history
# @history = self.histories.build
private # @history.status = self.status
# Creates an history for the issue # @history.author = self.author
#def build_history #end
# @history = self.histories.build
# @history.status = self.status
# @history.author = self.author
#end
end end
+27 -27
View File
@@ -1,29 +1,29 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueCategory < ActiveRecord::Base class IssueCategory < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
belongs_to :project belongs_to :project
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name, :scope => [:project_id] validates_uniqueness_of :name, :scope => [:project_id]
private private
def check_integrity def check_integrity
raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id]) raise "Can't delete category" if Issue.find(:first, :conditions => ["category_id=?", self.id])
end end
end end
+26 -26
View File
@@ -1,27 +1,27 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueCustomField < CustomField class IssueCustomField < CustomField
has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" has_and_belongs_to_many :projects, :join_table => "custom_fields_projects", :foreign_key => "custom_field_id"
has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :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 has_many :issues, :through => :issue_custom_values
def type_name def type_name
:label_issue_plural :label_issue_plural
end end
end end
+22 -22
View File
@@ -1,24 +1,24 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueHistory < ActiveRecord::Base class IssueHistory < ActiveRecord::Base
belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
belongs_to :issue belongs_to :issue
validates_presence_of :status validates_presence_of :status
end end
+49 -58
View File
@@ -1,60 +1,51 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class IssueStatus < ActiveRecord::Base class IssueStatus < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
has_many :workflows, :foreign_key => "old_status_id" has_many :workflows, :foreign_key => "old_status_id"
acts_as_list acts_as_list
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name validates_uniqueness_of :name
validates_format_of :name, :with => /^[\w\s\'\-]*$/i validates_format_of :name, :with => /^[\w\s\'\-]*$/i
validates_length_of :html_color, :is => 6 validates_length_of :html_color, :is => 6
validates_format_of :html_color, :with => /^[a-f0-9]*$/i validates_format_of :html_color, :with => /^[a-f0-9]*$/i
def before_save def before_save
IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default? IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default?
end end
# Returns the default status for new issues # Returns the default status for new issues
def self.default def self.default
find(:first, :conditions =>["is_default=?", true]) find(:first, :conditions =>["is_default=?", true])
end end
# Returns an array of all statuses the given role can switch to # Returns an array of all statuses the given role can switch to
# Uses association cache when called more than one time def new_statuses_allowed_to(role, tracker)
def new_statuses_allowed_to(role, tracker) statuses = []
new_statuses = [self] for workflow in self.workflows
new_statuses += workflows.select {|w| w.role_id == role.id && w.tracker_id == tracker.id}.collect{|w| w.new_status} if role && tracker statuses << workflow.new_status if workflow.role_id == role.id and workflow.tracker_id == tracker.id
new_statuses.sort{|x, y| x.position <=> y.position } end unless role.nil? or tracker.nil?
end statuses
end
# Same thing as above but uses a database query
# More efficient than the previous method if called just once private
def find_new_statuses_allowed_to(role, tracker) def check_integrity
new_statuses = [self] raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id])
new_statuses += workflows.find(:all,
:include => :new_status,
:conditions => ["role_id=? and tracker_id=?", role.id, tracker.id]).collect{ |w| w.new_status } if role && tracker
new_statuses.sort{|x, y| x.position <=> y.position }
end
private
def check_integrity
raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id])
end end
end end
-4
View File
@@ -17,10 +17,6 @@
class Journal < ActiveRecord::Base class Journal < ActiveRecord::Base
belongs_to :journalized, :polymorphic => true belongs_to :journalized, :polymorphic => true
# added as a quick fix to allow eager loading of the polymorphic association
# since always associated to an issue, for now
belongs_to :issue, :foreign_key => :journalized_id
belongs_to :user belongs_to :user
has_many :details, :class_name => "JournalDetail", :dependent => :delete_all has_many :details, :class_name => "JournalDetail", :dependent => :delete_all
end end
+79 -79
View File
@@ -1,88 +1,88 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Mailer < ActionMailer::Base class Mailer < ActionMailer::Base
helper IssuesHelper helper IssuesHelper
def issue_add(issue) def issue_add(issue)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
# Sends to all project members # Sends to all project members
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
@body['issue'] = issue @body['issue'] = issue
end end
def issue_edit(journal) def issue_edit(journal)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
# Sends to all project members # Sends to all project members
issue = journal.journalized issue = journal.journalized
@recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact @recipients = issue.project.members.collect { |m| m.user.mail if m.user.mail_notification }.compact
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}" @subject = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] #{issue.status.name} - #{issue.subject}"
@body['issue'] = issue @body['issue'] = issue
@body['journal']= journal @body['journal']= journal
end end
def document_add(document) def document_add(document)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
@recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact @recipients = document.project.users.collect { |u| u.mail if u.mail_notification }.compact
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}" @subject = "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}"
@body['document'] = document @body['document'] = document
end end
def attachments_add(attachments) def attachments_add(attachments)
set_language_if_valid(Setting.default_language) set_language_if_valid(Setting.default_language)
container = attachments.first.container container = attachments.first.container
url = "http://#{Setting.host_name}/" url = "http://#{Setting.host_name}/"
added_to = "" added_to = ""
case container.class.to_s case container.class.to_s
when 'Version' when 'Version'
url << "projects/list_files/#{container.project_id}" url << "projects/list_files/#{container.project_id}"
added_to = "#{l(:label_version)}: #{container.name}" added_to = "#{l(:label_version)}: #{container.name}"
when 'Document' when 'Document'
url << "documents/show/#{container.id}" url << "documents/show/#{container.id}"
added_to = "#{l(:label_document)}: #{container.title}" added_to = "#{l(:label_document)}: #{container.title}"
when 'Issue' when 'Issue'
url << "issues/show/#{container.id}" url << "issues/show/#{container.id}"
added_to = "#{container.tracker.name} ##{container.id}: #{container.subject}" added_to = "#{container.tracker.name} ##{container.id}: #{container.subject}"
end end
@recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact @recipients = container.project.users.collect { |u| u.mail if u.mail_notification }.compact
@from = Setting.mail_from @from = Setting.mail_from
@subject = "[#{container.project.name}] #{l(:label_attachment_new)}" @subject = "[#{container.project.name}] #{l(:label_attachment_new)}"
@body['attachments'] = attachments @body['attachments'] = attachments
@body['url'] = url @body['url'] = url
@body['added_to'] = added_to @body['added_to'] = added_to
end end
def lost_password(token) def lost_password(token)
set_language_if_valid(token.user.language) set_language_if_valid(token.user.language)
@recipients = token.user.mail @recipients = token.user.mail
@from = Setting.mail_from @from = Setting.mail_from
@subject = l(:mail_subject_lost_password) @subject = l(:mail_subject_lost_password)
@body['token'] = token @body['token'] = token
end end
def register(token) def register(token)
set_language_if_valid(token.user.language) set_language_if_valid(token.user.language)
@recipients = token.user.mail @recipients = token.user.mail
@from = Setting.mail_from @from = Setting.mail_from
@subject = l(:mail_subject_register) @subject = l(:mail_subject_register)
@body['token'] = token @body['token'] = token
end end
end end
+27 -27
View File
@@ -1,29 +1,29 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Member < ActiveRecord::Base class Member < ActiveRecord::Base
belongs_to :user belongs_to :user
belongs_to :role belongs_to :role
belongs_to :project belongs_to :project
validates_presence_of :role, :user, :project validates_presence_of :role, :user, :project
validates_uniqueness_of :user_id, :scope => :project_id validates_uniqueness_of :user_id, :scope => :project_id
def name def name
self.user.display_name self.user.display_name
end end
end end
+27 -27
View File
@@ -1,29 +1,29 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class News < ActiveRecord::Base class News < ActiveRecord::Base
belongs_to :project belongs_to :project
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on"
validates_presence_of :title, :description validates_presence_of :title, :description
# returns latest news for projects visible by user # returns latest news for projects visible by user
def self.latest(user=nil, count=5) def self.latest(user=nil, count=5)
find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "news.created_on DESC")
end end
end end
+63 -64
View File
@@ -1,66 +1,65 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Permission < ActiveRecord::Base class Permission < ActiveRecord::Base
has_and_belongs_to_many :roles has_and_belongs_to_many :roles
validates_presence_of :controller, :action, :description validates_presence_of :controller, :action, :description
GROUPS = { GROUPS = {
100 => :label_project, 100 => :label_project,
200 => :label_member_plural, 200 => :label_member_plural,
300 => :label_version_plural, 300 => :label_version_plural,
400 => :label_issue_category_plural, 400 => :label_issue_category_plural,
600 => :label_query_plural, 600 => :label_query_plural,
1000 => :label_issue_plural, 1000 => :label_issue_plural,
1100 => :label_news_plural, 1100 => :label_news_plural,
1200 => :label_document_plural, 1200 => :label_document_plural,
1300 => :label_attachment_plural, 1300 => :label_attachment_plural,
1400 => :label_repository, 1400 => :label_repository
1500 => :label_time_tracking }.freeze
}.freeze
@@cached_perms_for_public = nil
@@cached_perms_for_public = nil @@cached_perms_for_roles = nil
@@cached_perms_for_roles = nil
def name
def name self.controller + "/" + self.action
self.controller + "/" + self.action end
end
def group_id
def group_id (self.sort / 100)*100
(self.sort / 100)*100 end
end
def self.allowed_to_public(action)
def self.allowed_to_public(action) @@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"}
@@cached_perms_for_public ||= find(:all, :conditions => ["is_public=?", true]).collect {|p| "#{p.controller}/#{p.action}"} @@cached_perms_for_public.include? action
@@cached_perms_for_public.include? action end
end
def self.allowed_to_role(action, role)
def self.allowed_to_role(action, role) @@cached_perms_for_roles ||=
@@cached_perms_for_roles ||= begin
begin perms = {}
perms = {} find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } }
find(:all, :include => :roles).each {|p| perms.store "#{p.controller}/#{p.action}", p.roles.collect {|r| r.id } } perms
perms end
end allowed_to_public(action) or (@@cached_perms_for_roles[action] and @@cached_perms_for_roles[action].include? role)
allowed_to_public(action) or (role && @@cached_perms_for_roles[action] && @@cached_perms_for_roles[action].include?(role.id)) end
end
def self.allowed_to_role_expired
def self.allowed_to_role_expired @@cached_perms_for_roles = nil
@@cached_perms_for_roles = nil
end end
end end
+68 -92
View File
@@ -1,94 +1,70 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Project < ActiveRecord::Base class Project < ActiveRecord::Base
has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC" has_many :versions, :dependent => :destroy, :order => "versions.effective_date DESC, versions.name DESC"
has_many :members, :dependent => :delete_all, :include => :user, :conditions => "#{User.table_name}.status=#{User::STATUS_ACTIVE}" has_many :members, :dependent => :delete_all, :include => :user, :conditions => "users.status=#{User::STATUS_ACTIVE}"
has_many :users, :through => :members has_many :users, :through => :members
has_many :custom_values, :dependent => :delete_all, :as => :customized has_many :custom_values, :dependent => :delete_all, :as => :customized
has_many :issues, :dependent => :destroy, :order => "#{Issue.table_name}.created_on DESC", :include => [:status, :tracker] has_many :issues, :dependent => :destroy, :order => "issues.created_on DESC", :include => [:status, :tracker]
has_many :time_entries, :dependent => :delete_all has_many :queries, :dependent => :delete_all
has_many :queries, :dependent => :delete_all has_many :documents, :dependent => :destroy
has_many :documents, :dependent => :destroy has_many :news, :dependent => :delete_all, :include => :author
has_many :news, :dependent => :delete_all, :include => :author has_many :issue_categories, :dependent => :delete_all, :order => "issue_categories.name"
has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name" has_one :repository, :dependent => :destroy
has_one :repository, :dependent => :destroy has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_projects', :association_foreign_key => 'custom_field_id'
has_one :wiki, :dependent => :destroy acts_as_tree :order => "name", :counter_cache => true
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id'
acts_as_tree :order => "name", :counter_cache => true validates_presence_of :name, :description
validates_uniqueness_of :name
validates_presence_of :name, :description, :identifier validates_associated :custom_values, :on => :update
validates_uniqueness_of :name, :identifier validates_associated :repository
validates_associated :custom_values, :on => :update validates_format_of :name, :with => /^[\w\s\'\-]*$/i
validates_associated :repository, :wiki
validates_length_of :name, :maximum => 30 # returns latest created projects
validates_format_of :name, :with => /^[\w\s\'\-]*$/i # non public projects will be returned only if user is a member of those
validates_length_of :description, :maximum => 255 def self.latest(user=nil, count=5)
validates_length_of :identifier, :in => 3..12 find(:all, :limit => count, :conditions => visible_by(user), :order => "projects.created_on DESC")
validates_format_of :identifier, :with => /^[a-z0-9\-]*$/ end
def identifier=(identifier) def self.visible_by(user=nil)
super unless identifier_frozen? if user && !user.memberships.empty?
end return ["projects.is_public = ? or projects.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true]
else
def identifier_frozen? return ["projects.is_public = ?", true]
errors[:identifier].nil? && !(new_record? || identifier.blank?) end
end end
def issues_with_subprojects(include_subprojects=false) # Returns an array of all custom fields enabled for project issues
conditions = nil # (explictly associated custom fields and custom fields enabled for all projects)
if include_subprojects && children.size > 0 def custom_fields_for_issues(tracker)
ids = [id] + children.collect {|c| c.id} tracker.custom_fields.find(:all, :include => :projects,
conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"] :conditions => ["is_for_all=? or project_id=?", true, self.id])
else #(CustomField.for_all + custom_fields).uniq
conditions = ["#{Issue.table_name}.project_id = ?", id] end
end
Issue.with_scope :find => { :conditions => conditions } do def all_custom_fields
yield @all_custom_fields ||= IssueCustomField.find(:all, :include => :projects,
end :conditions => ["is_for_all=? or project_id=?", true, self.id])
end end
# returns latest created projects protected
# non public projects will be returned only if user is a member of those def validate
def self.latest(user=nil, count=5) errors.add(parent_id, " must be a root project") if parent and parent.parent
find(:all, :limit => count, :conditions => visible_by(user), :order => "created_on DESC") errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
end
def self.visible_by(user=nil)
if user && !user.memberships.empty?
return ["#{Project.table_name}.is_public = ? or #{Project.table_name}.id IN (#{user.memberships.collect{|m| m.project_id}.join(',')})", true]
else
return ["#{Project.table_name}.is_public = ?", true]
end
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)
all_custom_fields.select {|c| tracker.custom_fields.include? c }
end
def all_custom_fields
@all_custom_fields ||= (IssueCustomField.for_all + custom_fields).uniq
end
protected
def validate
errors.add(parent_id, " must be a root project") if parent and parent.parent
errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0
end end
end end
+22 -22
View File
@@ -1,22 +1,22 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class ProjectCustomField < CustomField class ProjectCustomField < CustomField
def type_name def type_name
:label_project_plural :label_project_plural
end end
end end
+17 -32
View File
@@ -45,7 +45,6 @@ class Query < ActiveRecord::Base
@@operators_by_filter_type = { :list => [ "=", "!" ], @@operators_by_filter_type = { :list => [ "=", "!" ],
:list_status => [ "o", "=", "!", "c", "*" ], :list_status => [ "o", "=", "!", "c", "*" ],
:list_optional => [ "=", "!", "!*", "*" ], :list_optional => [ "=", "!", "!*", "*" ],
:list_one_or_more => [ "*", "=" ],
:date => [ "<t+", ">t+", "t+", "t", ">t-", "<t-", "t-" ], :date => [ "<t+", ">t+", "t+", "t", ">t-", "<t-", "t-" ],
:date_past => [ ">t-", "<t-", "t-", "t" ], :date_past => [ ">t-", "<t-", "t-", "t" ],
:text => [ "~", "!~" ] } :text => [ "~", "!~" ] }
@@ -84,9 +83,6 @@ class Query < ActiveRecord::Base
@available_filters["author_id"] = { :type => :list, :order => 5, :values => @project.users.collect{|s| [s.name, s.id.to_s] } } @available_filters["author_id"] = { :type => :list, :order => 5, :values => @project.users.collect{|s| [s.name, s.id.to_s] } }
@available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } } @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } }
@available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.collect{|s| [s.name, s.id.to_s] } } @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.collect{|s| [s.name, s.id.to_s] } }
unless @project.children.empty?
@available_filters["subproject_id"] = { :type => :list_one_or_more, :order => 13, :values => @project.children.collect{|s| [s.name, s.id.to_s] } }
end
# remove category filter if no category defined # remove category filter if no category defined
@available_filters.delete "category_id" if @available_filters["category_id"][:values].empty? @available_filters.delete "category_id" if @available_filters["category_id"][:values].empty?
end end
@@ -127,54 +123,43 @@ class Query < ActiveRecord::Base
end end
def statement def statement
sql = "1=1" sql = "1=1"
if has_filter?("subproject_id") sql << " AND issues.project_id=%d" % project.id if project
subproject_ids = []
if operator_for("subproject_id") == "="
subproject_ids = values_for("subproject_id").each(&:to_i)
else
subproject_ids = project.children.collect{|p| p.id}
end
sql << " AND #{Issue.table_name}.project_id IN (%d,%s)" % [project.id, subproject_ids.join(",")] if project
else
sql << " AND #{Issue.table_name}.project_id=%d" % project.id if project
end
filters.each_key do |field| filters.each_key do |field|
next if field == "subproject_id"
v = values_for field v = values_for field
next unless v and !v.empty? next unless v and !v.empty?
sql = sql + " AND " unless sql.empty? sql = sql + " AND " unless sql.empty?
case operator_for field case operator_for field
when "=" when "="
sql = sql + "#{Issue.table_name}.#{field} IN (" + v.each(&:to_i).join(",") + ")" sql = sql + "issues.#{field} IN (" + v.each(&:to_i).join(",") + ")"
when "!" when "!"
sql = sql + "#{Issue.table_name}.#{field} NOT IN (" + v.each(&:to_i).join(",") + ")" sql = sql + "issues.#{field} NOT IN (" + v.each(&:to_i).join(",") + ")"
when "!*" when "!*"
sql = sql + "#{Issue.table_name}.#{field} IS NULL" sql = sql + "issues.#{field} IS NULL"
when "*" when "*"
sql = sql + "#{Issue.table_name}.#{field} IS NOT NULL" sql = sql + "issues.#{field} IS NOT NULL"
when "o" when "o"
sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id" sql = sql + "issue_statuses.is_closed=#{connection.quoted_false}" if field == "status_id"
when "c" when "c"
sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id" sql = sql + "issue_statuses.is_closed=#{connection.quoted_true}" if field == "status_id"
when ">t-" when ">t-"
sql = sql + "#{Issue.table_name}.#{field} >= '%s'" % connection.quoted_date(Date.today - v.first.to_i) sql = sql + "issues.#{field} >= '%s'" % connection.quoted_date(Date.today - v.first.to_i)
when "<t-" when "<t-"
sql = sql + "#{Issue.table_name}.#{field} <= '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'" sql = sql + "issues.#{field} <= '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'"
when "t-" when "t-"
sql = sql + "#{Issue.table_name}.#{field} = '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'" sql = sql + "issues.#{field} = '" + (Date.today - v.first.to_i).strftime("%Y-%m-%d") + "'"
when ">t+" when ">t+"
sql = sql + "#{Issue.table_name}.#{field} >= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" sql = sql + "issues.#{field} >= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
when "<t+" when "<t+"
sql = sql + "#{Issue.table_name}.#{field} <= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" sql = sql + "issues.#{field} <= '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
when "t+" when "t+"
sql = sql + "#{Issue.table_name}.#{field} = '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'" sql = sql + "issues.#{field} = '" + (Date.today + v.first.to_i).strftime("%Y-%m-%d") + "'"
when "t" when "t"
sql = sql + "#{Issue.table_name}.#{field} = '%s'" % connection.quoted_date(Date.today) sql = sql + "issues.#{field} = '%s'" % connection.quoted_date(Date.today)
when "~" when "~"
sql = sql + "#{Issue.table_name}.#{field} LIKE '%#{connection.quote_string(v.first)}%'" sql = sql + "issues.#{field} LIKE '%#{connection.quote_string(v.first)}%'"
when "!~" when "!~"
sql = sql + "#{Issue.table_name}.#{field} NOT LIKE '%#{connection.quote_string(v.first)}%'" sql = sql + "issues.#{field} NOT LIKE '%#{connection.quote_string(v.first)}%'"
end end
end if filters and valid? end if filters and valid?
sql sql
+4 -64
View File
@@ -1,5 +1,5 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
@@ -17,72 +17,12 @@
class Repository < ActiveRecord::Base class Repository < ActiveRecord::Base
belongs_to :project belongs_to :project
has_many :changesets, :dependent => :destroy, :order => 'revision DESC'
has_many :changes, :through => :changesets
has_one :latest_changeset, :class_name => 'Changeset', :foreign_key => :repository_id, :order => 'revision DESC'
attr_protected :root_url
validates_presence_of :url validates_presence_of :url
validates_format_of :url, :with => /^(http|https|svn|file):\/\/.+/i validates_format_of :url, :with => /^(http|https|svn|file):\/\/.+/i
@scm = nil
def scm def scm
@scm ||= SvnRepos::Base.new url, root_url, login, password @scm ||= SvnRepos::Base.new url
update_attribute(:root_url, @scm.root_url) if root_url.blank?
@scm
end
def url=(str)
super if root_url.blank?
end
def changesets_with_path(path="")
path = "/#{path}%"
path = url.gsub(/^#{root_url}/, '') + path if root_url && root_url != url
path.squeeze!("/")
Changeset.with_scope(:find => { :include => :changes, :conditions => ["#{Change.table_name}.path LIKE ?", path] }) do
yield
end
end
def fetch_changesets
scm_info = scm.info
if scm_info
lastrev_identifier = scm_info.lastrev.identifier.to_i
if latest_changeset.nil? || latest_changeset.revision < lastrev_identifier
logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
identifier_from = latest_changeset ? latest_changeset.revision + 1 : 1
while (identifier_from <= lastrev_identifier)
# loads changesets by batches of 200
identifier_to = [identifier_from + 199, lastrev_identifier].min
revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true)
transaction do
revisions.reverse_each do |revision|
changeset = Changeset.create(:repository => self,
:revision => revision.identifier,
:committer => revision.author,
:committed_on => revision.time,
:comment => revision.message)
revision.paths.each do |change|
Change.create(:changeset => changeset,
:action => change[:action],
:path => change[:path],
:from_path => change[:from_path],
:from_revision => change[:from_revision])
end
end
end unless revisions.nil?
identifier_from = identifier_to + 1
end
end
end
end
# fetch new changesets for all repositories
# can be called periodically by an external script
# eg. ruby script/runner "Repository.fetch_changesets"
def self.fetch_changesets
find(:all).each(&:fetch_changesets)
end end
end end
+31 -35
View File
@@ -1,37 +1,33 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Role < ActiveRecord::Base class Role < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
has_and_belongs_to_many :permissions has_and_belongs_to_many :permissions
has_many :workflows, :dependent => :delete_all has_many :workflows, :dependent => :delete_all
has_many :members has_many :members
acts_as_list acts_as_list
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name validates_uniqueness_of :name
validates_format_of :name, :with => /^[\w\s\'\-]*$/i validates_format_of :name, :with => /^[\w\s\'\-]*$/i
def <=>(role) private
position <=> role.position def check_integrity
end raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id])
private
def check_integrity
raise "Can't delete role" if Member.find(:first, :conditions =>["role_id=?", self.id])
end end
end end
+213 -430
View File
@@ -1,431 +1,214 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require 'rexml/document' require 'rexml/document'
require 'cgi'
module SvnRepos
module SvnRepos
class CommandFailed < StandardError #:nodoc:
class CommandFailed < StandardError #:nodoc: end
end
class Base
class Base @url = nil
@login = nil
def initialize(url, root_url=nil, login=nil, password=nil) @password = nil
@url = url
@login = login if login && !login.empty? def initialize(url, login=nil, password=nil)
@password = (password || "") if @login @url = url
@root_url = root_url.blank? ? retrieve_root_url : root_url @login = login if login && !login.empty?
end @password = (password || "") if @login
end
def root_url
@root_url # Returns the entry identified by path and revision identifier
end # or nil if entry doesn't exist in the repository
def entry(path=nil, identifier=nil)
def url e = entries(path, identifier)
@url e ? e.first : nil
end end
# get info about the svn repository # Returns an Entries collection
def info # or nil if the given path doesn't exist in the repository
cmd = "svn info --xml #{target('')}" def entries(path=nil, identifier=nil)
cmd << " --username #{@login} --password #{@password}" if @login path ||= ''
info = nil identifier = 'HEAD' unless identifier and identifier > 0
shellout(cmd) do |io| entries = Entries.new
begin cmd = "svn list --xml #{target(path)}@#{identifier}"
doc = REXML::Document.new(io) shellout(cmd) do |io|
#root_url = doc.elements["info/entry/repository/root"].text begin
info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text, doc = REXML::Document.new(io)
:lastrev => Revision.new({ doc.elements.each("lists/list/entry") do |entry|
:identifier => doc.elements["info/entry/commit"].attributes['revision'], entries << Entry.new({:name => entry.elements['name'].text,
:time => Time.parse(doc.elements["info/entry/commit/date"].text), :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text),
:author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "") :kind => entry.attributes['kind'],
}) :size => (entry.elements['size'] and entry.elements['size'].text).to_i,
}) :lastrev => Revision.new({
rescue :identifier => entry.elements['commit'].attributes['revision'],
end :time => Time.parse(entry.elements['commit'].elements['date'].text),
end :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "anonymous")
return nil if $? && $?.exitstatus != 0 })
info })
rescue Errno::ENOENT => e end
return nil rescue
end end
end
# Returns the entry identified by path and revision identifier return nil if $? && $?.exitstatus != 0
# or nil if entry doesn't exist in the repository entries.sort_by_name
def entry(path=nil, identifier=nil) rescue Errno::ENOENT => e
e = entries(path, identifier) raise CommandFailed
e ? e.first : nil end
end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
# Returns an Entries collection path ||= ''
# or nil if the given path doesn't exist in the repository identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
def entries(path=nil, identifier=nil) identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
path ||= '' revisions = Revisions.new
identifier = 'HEAD' unless identifier and identifier > 0 cmd = "svn log --xml -r #{identifier_from}:#{identifier_to} "
entries = Entries.new cmd << "--verbose " if options[:with_paths]
cmd = "svn list --xml #{target(path)}@#{identifier}" cmd << target(path)
cmd << " --username #{@login} --password #{@password}" if @login shellout(cmd) do |io|
shellout(cmd) do |io| begin
begin doc = REXML::Document.new(io)
doc = REXML::Document.new(io) doc.elements.each("log/logentry") do |logentry|
doc.elements.each("lists/list/entry") do |entry| paths = []
entries << Entry.new({:name => entry.elements['name'].text, logentry.elements.each("paths/path") do |path|
:path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text), paths << {:action => path.attributes['action'],
:kind => entry.attributes['kind'], :path => path.text
:size => (entry.elements['size'] and entry.elements['size'].text).to_i, }
:lastrev => Revision.new({ end
:identifier => entry.elements['commit'].attributes['revision'], paths.sort! { |x,y| x[:path] <=> y[:path] }
:time => Time.parse(entry.elements['commit'].elements['date'].text),
:author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "") revisions << Revision.new({:identifier => logentry.attributes['revision'],
}) :author => (logentry.elements['author'] ? logentry.elements['author'].text : "anonymous"),
}) :time => Time.parse(logentry.elements['date'].text),
end :message => logentry.elements['msg'].text,
rescue :paths => paths
end })
end end
return nil if $? && $?.exitstatus != 0 rescue
entries.sort_by_name end
rescue Errno::ENOENT => e end
raise CommandFailed return nil if $? && $?.exitstatus != 0
end revisions
rescue Errno::ENOENT => e
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) raise CommandFailed
path ||= '' end
identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
identifier_to = 1 unless identifier_to and identifier_to.to_i > 0 def diff(path, identifier_from, identifier_to=nil)
revisions = Revisions.new path ||= ''
cmd = "svn log --xml -r #{identifier_from}:#{identifier_to}" if identifier_to and identifier_to.to_i > 0
cmd << " --username #{@login} --password #{@password}" if @login identifier_to = identifier_to.to_i
cmd << " --verbose " if options[:with_paths] else
cmd << target(path) identifier_to = identifier_from.to_i - 1
shellout(cmd) do |io| end
begin cmd = "svn diff -r "
doc = REXML::Document.new(io) cmd << "#{identifier_to}:"
doc.elements.each("log/logentry") do |logentry| cmd << "#{identifier_from}"
paths = [] cmd << "#{target(path)}@#{identifier_from}"
logentry.elements.each("paths/path") do |path| diff = []
paths << {:action => path.attributes['action'], shellout(cmd) do |io|
:path => path.text, io.each_line do |line|
:from_path => path.attributes['copyfrom-path'], diff << line
:from_revision => path.attributes['copyfrom-rev'] end
} end
end return nil if $? && $?.exitstatus != 0
paths.sort! { |x,y| x[:path] <=> y[:path] } diff
rescue Errno::ENOENT => e
revisions << Revision.new({:identifier => logentry.attributes['revision'], raise CommandFailed
:author => (logentry.elements['author'] ? logentry.elements['author'].text : ""), end
:time => Time.parse(logentry.elements['date'].text),
:message => logentry.elements['msg'].text, def cat(path, identifier=nil)
:paths => paths identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
}) cmd = "svn cat #{target(path)}@#{identifier}"
end cat = nil
rescue shellout(cmd) do |io|
end cat = io.read
end end
return nil if $? && $?.exitstatus != 0 return nil if $? && $?.exitstatus != 0
revisions cat
rescue Errno::ENOENT => e rescue Errno::ENOENT => e
raise CommandFailed raise CommandFailed
end end
def diff(path, identifier_from, identifier_to=nil, type="inline") private
path ||= '' def target(path)
if identifier_to and identifier_to.to_i > 0 " \"" << "#{@url}/#{path}".gsub(/["'?<>\*]/, '') << "\""
identifier_to = identifier_to.to_i end
else
identifier_to = identifier_from.to_i - 1 def logger
end RAILS_DEFAULT_LOGGER
cmd = "svn diff -r " end
cmd << "#{identifier_to}:"
cmd << "#{identifier_from}" def shellout(cmd, &block)
cmd << "#{target(path)}@#{identifier_from}" logger.debug "Shelling out: #{cmd}" if logger && logger.debug?
cmd << " --username #{@login} --password #{@password}" if @login IO.popen(cmd) do |io|
diff = [] block.call(io) if block_given?
shellout(cmd) do |io| end
io.each_line do |line| end
diff << line end
end
end class Entries < Array
return nil if $? && $?.exitstatus != 0 def sort_by_name
DiffTableList.new diff, type sort {|x,y|
if x.kind == y.kind
rescue Errno::ENOENT => e x.name <=> y.name
raise CommandFailed else
end x.kind <=> y.kind
end
def cat(path, identifier=nil) }
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" end
cmd = "svn cat #{target(path)}@#{identifier}"
cmd << " --username #{@login} --password #{@password}" if @login def revisions
cat = nil revisions ||= Revisions.new(collect{|entry| entry.lastrev})
shellout(cmd) do |io| end
cat = io.read end
end
return nil if $? && $?.exitstatus != 0 class Entry
cat attr_accessor :name, :path, :kind, :size, :lastrev
rescue Errno::ENOENT => e def initialize(attributes={})
raise CommandFailed self.name = attributes[:name] if attributes[:name]
end self.path = attributes[:path] if attributes[:path]
self.kind = attributes[:kind] if attributes[:kind]
private self.size = attributes[:size].to_i if attributes[:size]
def retrieve_root_url self.lastrev = attributes[:lastrev]
info = self.info end
info ? info.root_url : nil
end def is_file?
'file' == self.kind
def target(path) end
path ||= ""
base = path.match(/^\//) ? root_url : url def is_dir?
" \"" << "#{base}/#{path}".gsub(/["'?<>\*]/, '') << "\"" 'dir' == self.kind
end end
end
def logger
RAILS_DEFAULT_LOGGER class Revisions < Array
end def latest
sort {|x,y| x.time <=> y.time}.last
def shellout(cmd, &block) end
logger.debug "Shelling out: #{cmd}" if logger && logger.debug? end
IO.popen(cmd, "r+") do |io|
io.close_write class Revision
block.call(io) if block_given? attr_accessor :identifier, :author, :time, :message, :paths
end def initialize(attributes={})
end self.identifier = attributes[:identifier]
end self.author = attributes[:author]
self.time = attributes[:time]
class Entries < Array self.message = attributes[:message] || ""
def sort_by_name self.paths = attributes[:paths]
sort {|x,y| end
if x.kind == y.kind end
x.name <=> y.name
else
x.kind <=> y.kind
end
}
end
def revisions
revisions ||= Revisions.new(collect{|entry| entry.lastrev})
end
end
class Info
attr_accessor :root_url, :lastrev
def initialize(attributes={})
self.root_url = attributes[:root_url] if attributes[:root_url]
self.lastrev = attributes[:lastrev]
end
end
class Entry
attr_accessor :name, :path, :kind, :size, :lastrev
def initialize(attributes={})
self.name = attributes[:name] if attributes[:name]
self.path = attributes[:path] if attributes[:path]
self.kind = attributes[:kind] if attributes[:kind]
self.size = attributes[:size].to_i if attributes[:size]
self.lastrev = attributes[:lastrev]
end
def is_file?
'file' == self.kind
end
def is_dir?
'dir' == self.kind
end
end
class Revisions < Array
def latest
sort {|x,y| x.time <=> y.time}.last
end
end
class Revision
attr_accessor :identifier, :author, :time, :message, :paths
def initialize(attributes={})
self.identifier = attributes[:identifier]
self.author = attributes[:author]
self.time = attributes[:time]
self.message = attributes[:message] || ""
self.paths = attributes[:paths]
end
end
# A line of Diff
class Diff
attr_accessor :nb_line_left
attr_accessor :line_left
attr_accessor :nb_line_right
attr_accessor :line_right
attr_accessor :type_diff_right
attr_accessor :type_diff_left
def initialize ()
self.nb_line_left = ''
self.nb_line_right = ''
self.line_left = ''
self.line_right = ''
self.type_diff_right = ''
self.type_diff_left = ''
end
def inspect
puts '### Start Line Diff ###'
puts self.nb_line_left
puts self.line_left
puts self.nb_line_right
puts self.line_right
end
end
class DiffTableList < Array
def initialize (diff, type="inline")
diff_table = DiffTable.new type
diff.each do |line|
if line =~ /^Index: (.*)$/
self << diff_table if diff_table.length > 1
diff_table = DiffTable.new type
end
a = diff_table.add_line line
end
self << diff_table
end
end
# Class for create a Diff
class DiffTable < Hash
attr_reader :file_name, :line_num_l, :line_num_r
# Initialize with a Diff file and the type of Diff View
# The type view must be inline or sbs (side_by_side)
def initialize (type="inline")
@parsing = false
@nb_line = 1
@start = false
@before = 'same'
@second = true
@type = type
end
# Function for add a line of this Diff
def add_line(line)
unless @parsing
if line =~ /^Index: (.*)$/
@file_name = $1
return false
elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
@line_num_l = $2.to_i
@line_num_r = $5.to_i
@parsing = true
end
else
if line =~ /^_+$/
self.delete(self.keys.sort.last)
@parsing = false
return false
elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/
@line_num_l = $2.to_i
@line_num_r = $5.to_i
else
@nb_line += 1 if parse_line(line, @type)
end
end
return true
end
def inspect
puts '### DIFF TABLE ###'
puts "file : #{file_name}"
self.each do |d|
d.inspect
end
end
private
# Test if is a Side By Side type
def sbs?(type, func)
if @start and type == "sbs"
if @before == func and @second
tmp_nb_line = @nb_line
self[tmp_nb_line] = Diff.new
else
@second = false
tmp_nb_line = @start
@start += 1
@nb_line -= 1
end
else
tmp_nb_line = @nb_line
@start = @nb_line
self[tmp_nb_line] = Diff.new
@second = true
end
unless self[tmp_nb_line]
@nb_line += 1
self[tmp_nb_line] = Diff.new
else
self[tmp_nb_line]
end
end
# Escape the HTML for the diff
def escapeHTML(line)
CGI.escapeHTML(line).gsub(/\s/, '&nbsp;')
end
def parse_line (line, type="inline")
if line[0, 1] == "+"
diff = sbs? type, 'add'
@before = 'add'
diff.line_left = escapeHTML line[1..-1]
diff.nb_line_left = @line_num_l
diff.type_diff_left = 'diff_in'
@line_num_l += 1
true
elsif line[0, 1] == "-"
diff = sbs? type, 'remove'
@before = 'remove'
diff.line_right = escapeHTML line[1..-1]
diff.nb_line_right = @line_num_r
diff.type_diff_right = 'diff_out'
@line_num_r += 1
true
elsif line[0, 1] =~ /\s/
@before = 'same'
@start = false
diff = Diff.new
diff.line_right = escapeHTML line[1..-1]
diff.nb_line_right = @line_num_r
diff.line_left = escapeHTML line[1..-1]
diff.nb_line_left = @line_num_l
self[@nb_line] = diff
@line_num_l += 1
@line_num_r += 1
true
else
false
end
end
end
end end
-33
View File
@@ -1,33 +0,0 @@
class TimeEntry < ActiveRecord::Base
# could have used polymorphic association
# project association here allows easy loading of time entries at project level with one database trip
belongs_to :project
belongs_to :issue
belongs_to :user
belongs_to :activity, :class_name => 'Enumeration', :foreign_key => :activity_id
attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek
validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on
validates_numericality_of :hours, :allow_nil => true
validates_length_of :comment, :maximum => 255
def before_validation
self.project = issue.project if issue && project.nil?
end
def validate
errors.add :hours, :activerecord_error_invalid if hours && (hours < 0 || hours >= 1000)
errors.add :project_id, :activerecord_error_invalid if project.nil?
errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project)
end
# tyear, tmonth, tweek assigned where setting spent_on attributes
# these attributes make time aggregations easier
def spent_on=(date)
super
self.tyear = spent_on ? spent_on.year : nil
self.tmonth = spent_on ? spent_on.month : nil
self.tweek = spent_on ? spent_on.cweek : nil
end
end
+1 -1
View File
@@ -31,7 +31,7 @@ class Token < ActiveRecord::Base
# Delete all expired tokens # Delete all expired tokens
def self.destroy_expired def self.destroy_expired
Token.delete_all ["action <> 'feeds' AND created_on < ?", Time.now - @@validity_time] Token.delete_all ["created_on < ?", Time.now - @@validity_time]
end end
private private
+31 -31
View File
@@ -1,33 +1,33 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Tracker < ActiveRecord::Base class Tracker < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
has_many :issues has_many :issues
has_many :workflows, :dependent => :delete_all has_many :workflows, :dependent => :delete_all
has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => 'custom_fields_trackers', :association_foreign_key => 'custom_field_id'
acts_as_list acts_as_list
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name validates_uniqueness_of :name
validates_format_of :name, :with => /^[\w\s\'\-]*$/i validates_format_of :name, :with => /^[\w\s\'\-]*$/i
private private
def check_integrity def check_integrity
raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id]) raise "Can't delete tracker" if Issue.find(:first, :conditions => ["tracker_id=?", self.id])
end end
end end
+140 -152
View File
@@ -1,154 +1,142 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang # Copyright (C) 2006-2007 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
require "digest/sha1" require "digest/sha1"
class User < ActiveRecord::Base class User < ActiveRecord::Base
has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => :delete_all has_many :memberships, :class_name => 'Member', :include => [ :project, :role ], :dependent => :delete_all
has_many :projects, :through => :memberships has_many :projects, :through => :memberships
has_many :custom_values, :dependent => :delete_all, :as => :customized has_many :custom_values, :dependent => :delete_all, :as => :customized
has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :preference, :dependent => :destroy, :class_name => 'UserPreference'
has_one :rss_key, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'" belongs_to :auth_source
belongs_to :auth_source
attr_accessor :password, :password_confirmation
attr_accessor :password, :password_confirmation attr_accessor :last_before_login_on
attr_accessor :last_before_login_on # Prevents unauthorized assignments
# Prevents unauthorized assignments attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
attr_protected :login, :admin, :password, :password_confirmation, :hashed_password
validates_presence_of :login, :firstname, :lastname, :mail
validates_presence_of :login, :firstname, :lastname, :mail validates_uniqueness_of :login, :mail
validates_uniqueness_of :login, :mail # Login must contain lettres, numbers, underscores only
# Login must contain lettres, numbers, underscores only validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i
validates_format_of :login, :with => /^[a-z0-9_\-@\.]+$/i validates_format_of :login, :with => /^[a-z0-9_\-@\.]+$/i
validates_length_of :login, :maximum => 30 validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
validates_format_of :firstname, :lastname, :with => /^[\w\s\'\-]*$/i # Password length between 4 and 12
validates_length_of :firstname, :lastname, :maximum => 30 validates_length_of :password, :in => 4..12, :allow_nil => true
validates_format_of :mail, :with => /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i validates_confirmation_of :password, :allow_nil => true
validates_length_of :mail, :maximum => 60 validates_associated :custom_values, :on => :update
# Password length between 4 and 12
validates_length_of :password, :in => 4..12, :allow_nil => true # Account statuses
validates_confirmation_of :password, :allow_nil => true STATUS_ACTIVE = 1
validates_associated :custom_values, :on => :update STATUS_REGISTERED = 2
STATUS_LOCKED = 3
# Account statuses
STATUS_ACTIVE = 1 def before_save
STATUS_REGISTERED = 2 # update hashed_password if password was set
STATUS_LOCKED = 3 self.hashed_password = User.hash_password(self.password) if self.password
end
def before_save
# update hashed_password if password was set def self.active
self.hashed_password = User.hash_password(self.password) if self.password with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
end yield
end
def self.active end
with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do
yield def self.find_active(*args)
end active do
end find(*args)
end
def self.find_active(*args) end
active do
find(*args) # Returns the user that matches provided login and password, or nil
end def self.try_to_login(login, password)
end user = find(:first, :conditions => ["login=?", login])
if user
# Returns the user that matches provided login and password, or nil # user is already in local database
def self.try_to_login(login, password) return nil if !user.active?
user = find(:first, :conditions => ["login=?", login]) if user.auth_source
if user # user has an external authentication method
# user is already in local database return nil unless user.auth_source.authenticate(login, password)
return nil if !user.active? else
if user.auth_source # authentication with local password
# user has an external authentication method return nil unless User.hash_password(password) == user.hashed_password
return nil unless user.auth_source.authenticate(login, password) end
else else
# authentication with local password # user is not yet registered, try to authenticate with available sources
return nil unless User.hash_password(password) == user.hashed_password attrs = AuthSource.authenticate(login, password)
end if attrs
else onthefly = new(*attrs)
# user is not yet registered, try to authenticate with available sources onthefly.login = login
attrs = AuthSource.authenticate(login, password) onthefly.language = Setting.default_language
if attrs if onthefly.save
onthefly = new(*attrs) user = find(:first, :conditions => ["login=?", login])
onthefly.login = login logger.info("User '#{user.login}' created on the fly.") if logger
onthefly.language = Setting.default_language end
if onthefly.save end
user = find(:first, :conditions => ["login=?", login]) end
logger.info("User '#{user.login}' created on the fly.") if logger user.update_attribute(:last_login_on, Time.now) if user
end user
end
end rescue => text
user.update_attribute(:last_login_on, Time.now) if user raise text
user end
rescue => text # Return user's full name for display
raise text def display_name
end firstname + " " + lastname
end
# Return user's full name for display
def display_name def name
firstname + " " + lastname display_name
end end
def name def active?
display_name self.status == STATUS_ACTIVE
end end
def active? def registered?
self.status == STATUS_ACTIVE self.status == STATUS_REGISTERED
end end
def registered? def locked?
self.status == STATUS_REGISTERED self.status == STATUS_LOCKED
end end
def locked? def check_password?(clear_password)
self.status == STATUS_LOCKED User.hash_password(clear_password) == self.hashed_password
end end
def check_password?(clear_password) def role_for_project(project_id)
User.hash_password(clear_password) == self.hashed_password @role_for_projects ||=
end begin
roles = {}
def role_for_project(project) self.memberships.each { |m| roles.store m.project_id, m.role_id }
member = memberships.detect {|m| m.project_id == project.id} roles
member ? member.role : nil end
end @role_for_projects[project_id]
end
def pref
self.preference ||= UserPreference.new(:user => self) def pref
end self.preference ||= UserPreference.new(:user => self)
end
def get_or_create_rss_key
self.rss_key || Token.create(:user => self, :action => 'feeds') private
end # Return password digest
def self.hash_password(clear_password)
def self.find_by_rss_key(key) Digest::SHA1.hexdigest(clear_password || "")
token = Token.find_by_value(key)
token && token.user.active? ? token.user : nil
end
def <=>(user)
lastname <=> user.lastname
end
private
# Return password digest
def self.hash_password(clear_password)
Digest::SHA1.hexdigest(clear_password || "")
end end
end end
+22 -22
View File
@@ -1,23 +1,23 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class UserCustomField < CustomField class UserCustomField < CustomField
def type_name def type_name
:label_user_plural :label_user_plural
end end
end end
+31 -39
View File
@@ -1,40 +1,32 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Version < ActiveRecord::Base class Version < ActiveRecord::Base
before_destroy :check_integrity before_destroy :check_integrity
belongs_to :project belongs_to :project
has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
has_many :attachments, :as => :container, :dependent => :destroy has_many :attachments, :as => :container, :dependent => :destroy
validates_presence_of :name validates_presence_of :name
validates_uniqueness_of :name, :scope => [:project_id] validates_uniqueness_of :name, :scope => [:project_id]
validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date validates_format_of :effective_date, :with => /^\d{4}-\d{2}-\d{2}$/, :message => :activerecord_error_not_a_date
def start_date private
effective_date def check_integrity
end raise "Can't delete version" if self.fixed_issues.find(:first)
end
def due_date
effective_date
end
private
def check_integrity
raise "Can't delete version" if self.fixed_issues.find(:first)
end
end end
-44
View File
@@ -1,44 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 Wiki < ActiveRecord::Base
belongs_to :project
has_many :pages, :class_name => 'WikiPage', :dependent => :destroy
validates_presence_of :start_page
# find the page with the given title
# if page doesn't exist, return a new page
def find_or_new_page(title)
title = Wiki.titleize(title || start_page)
find_page(title) || WikiPage.new(:wiki => self, :title => title)
end
# find the page with the given title
def find_page(title)
pages.find_by_title(Wiki.titleize(title || start_page))
end
# turn a string into a valid page title
def self.titleize(title)
# replace spaces with _ and remove unwanted caracters
title = title.gsub(/\s+/, '_').delete(',;|') if title
# upcase the first letter
title = title[0..0].upcase + title[1..-1] if title
title
end
end
-58
View File
@@ -1,58 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 'zlib'
class WikiContent < ActiveRecord::Base
belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id'
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
validates_presence_of :text
acts_as_versioned
class Version
belongs_to :author, :class_name => 'User', :foreign_key => 'author_id'
attr_protected :data
def text=(plain)
case Setting.wiki_compression
when 'gzip'
begin
self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION)
self.compression = 'gzip'
rescue
self.data = plain
self.compression = ''
end
else
self.data = plain
self.compression = ''
end
plain
end
def text
@text ||= case compression
when 'gzip'
Zlib::Inflate.inflate(data)
else
# uncompressed data
data
end
end
end
end
-44
View File
@@ -1,44 +0,0 @@
# redMine - project management software
# Copyright (C) 2006-2007 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 WikiPage < ActiveRecord::Base
belongs_to :wiki
has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy
validates_presence_of :title
validates_format_of :title, :with => /^[^,\s]*$/
validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false
validates_associated :content
def before_save
self.title = Wiki.titleize(title)
end
def pretty_title
WikiPage.pretty_title(title)
end
def content_for_version(version=nil)
result = content.versions.find_by_version(version.to_i) if version
result ||= content
result
end
def self.pretty_title(str)
(str && str.is_a?(String)) ? str.tr('_', ' ') : str
end
end
+23 -23
View File
@@ -1,24 +1,24 @@
# redMine - project management software # redMine - project management software
# Copyright (C) 2006 Jean-Philippe Lang # Copyright (C) 2006 Jean-Philippe Lang
# #
# This program is free software; you can redistribute it and/or # This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License # modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2 # as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version. # of the License, or (at your option) any later version.
# #
# This program is distributed in the hope that it will be useful, # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of # but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details. # GNU General Public License for more details.
# #
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
class Workflow < ActiveRecord::Base class Workflow < ActiveRecord::Base
belongs_to :role belongs_to :role
belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id' belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id'
belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id'
validates_presence_of :role, :old_status, :new_status validates_presence_of :role, :old_status, :new_status
end end
+20 -20
View File
@@ -1,24 +1,24 @@
<center> <center>
<div class="box login"> <div class="box login">
<h2 class="icon22 icon22-authent"><%=l(:label_please_login)%></h2> <h2 class="icon22 icon22-authent"><%=l(:label_please_login)%></h2>
<% form_tag({:action=> "login"}, :class => "tabular") do %> <% form_tag({:action=> "login"}, :class => "tabular") do %>
<p><label for="login"><%=l(:field_login)%>:</label> <p><label for="login"><%=l(:field_login)%>:</label>
<%= text_field_tag 'login', nil, :size => 25 %></p> <%= text_field_tag 'login', nil, :size => 25 %></p>
<p><label for="password"><%=l(:field_password)%>:</label> <p><label for="password"><%=l(:field_password)%>:</label>
<%= password_field_tag 'password', nil, :size => 25 %></p> <%= password_field_tag 'password', nil, :size => 25 %></p>
<p><center><input type="submit" name="login" value="<%=l(:button_login)%> &#187;" class="primary" /></center> <p><center><input type="submit" name="login" value="<%=l(:button_login)%> &#187;" class="primary" /></center>
<% end %> <% end %>
<br>
<% links = []
links << link_to(l(:label_register), :action => 'register') if Setting.self_registration?
links << link_to(l(:label_password_lost), :action => 'lost_password') if Setting.lost_password?
%>
<%= links.join(" | ") %>
</p>
<br> </div>
<% links = []
links << link_to(l(:label_register), :action => 'register') if Setting.self_registration?
links << link_to(l(:label_password_lost), :action => 'lost_password') if Setting.lost_password?
%>
<%= links.join(" | ") %>
</p>
</div>
</center> </center>
+13 -13
View File
@@ -1,14 +1,14 @@
<center> <center>
<div class="box login"> <div class="box login">
<h2><%=l(:label_password_lost)%></h2> <h2><%=l(:label_password_lost)%></h2>
<% form_tag({:action=> "lost_password"}, :class => "tabular") do %> <% form_tag({:action=> "lost_password"}, :class => "tabular") do %>
<p><label for="mail"><%=l(:field_mail)%> <span class="required">*</span></label> <p><label for="mail"><%=l(:field_mail)%> <span class="required">*</span></label>
<%= text_field_tag 'mail', nil, :size => 40 %></p> <%= text_field_tag 'mail', nil, :size => 40 %></p>
<p><center><%= submit_tag l(:button_submit) %></center></p> <p><center><%= submit_tag l(:button_submit) %></center></p>
<% end %> <% end %>
</div> </div>
</center> </center>
+9 -10
View File
@@ -1,22 +1,21 @@
<center> <center>
<div class="box login"> <div class="box login">
<h2><%=l(:label_password_lost)%></h2> <h2><%=l(:label_password_lost)%></h2>
<p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br /> <p><%=l(:field_login)%>: <strong><%= @user.login %></strong><br />
<%= error_messages_for 'user' %> <%= error_messages_for 'user' %>
<% form_tag({:token => @token.value}, :class => "tabular") do %> <% form_tag({:token => @token.value}, :class => "tabular") do %>
<p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label> <p><label for="new_password"><%=l(:field_new_password)%> <span class="required">*</span></label>
<%= password_field_tag 'new_password', nil, :size => 25 %><br /> <%= password_field_tag 'new_password', nil, :size => 25 %></p>
<em><%= l(:text_length_between, 4, 12) %></em></p>
<p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label> <p><label for="new_password_confirmation"><%=l(:field_password_confirmation)%> <span class="required">*</span></label>
<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p> <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %></p>
<p><center><%= submit_tag l(:button_save) %></center></p> <p><center><%= submit_tag l(:button_save) %></center></p>
<% end %> <% end %>
</div> </div>
</center> </center>
+9 -9
View File
@@ -7,7 +7,7 @@
<!--[form:user]--> <!--[form:user]-->
<p><label for="user_login"><%=l(:field_login)%> <span class="required">*</span></label> <p><label for="user_login"><%=l(:field_login)%> <span class="required">*</span></label>
<%= text_field 'user', 'login', :size => 25 %></p> <%= text_field 'user', 'login', :size => 25 %></p>
<p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label> <p><label for="password"><%=l(:field_password)%> <span class="required">*</span></label>
<%= password_field_tag 'password', nil, :size => 25 %></p> <%= password_field_tag 'password', nil, :size => 25 %></p>
@@ -16,22 +16,22 @@
<p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label> <p><label for="user_firstname"><%=l(:field_firstname)%> <span class="required">*</span></label>
<%= text_field 'user', 'firstname' %></p> <%= text_field 'user', 'firstname' %></p>
<p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label> <p><label for="user_lastname"><%=l(:field_lastname)%> <span class="required">*</span></label>
<%= text_field 'user', 'lastname' %></p> <%= text_field 'user', 'lastname' %></p>
<p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label> <p><label for="user_mail"><%=l(:field_mail)%> <span class="required">*</span></label>
<%= text_field 'user', 'mail' %></p> <%= text_field 'user', 'mail' %></p>
<p><label for="user_language"><%=l(:field_language)%></label> <p><label for="user_language"><%=l(:field_language)%></label>
<%= select("user", "language", lang_options_for_select) %></p> <%= select("user", "language", lang_options_for_select) %></p>
<% for @custom_value in @custom_values %> <% for @custom_value in @custom_values %>
<p><%= custom_field_tag_with_label @custom_value %></p> <p><%= custom_field_tag_with_label @custom_value %></p>
<% end %> <% end %>
<p><label for="user_mail_notification"><%=l(:field_mail_notification)%></label> <p><label for="user_mail_notification"><%=l(:field_mail_notification)%></label>
<%= check_box 'user', 'mail_notification' %></p> <%= check_box 'user', 'mail_notification' %></p>
<!--[eoform:user]--> <!--[eoform:user]-->
</div> </div>
+25 -25
View File
@@ -1,26 +1,26 @@
<h2><%= @user.display_name %></h2> <h2><%= @user.display_name %></h2>
<p> <p>
<%= mail_to @user.mail unless @user.pref.hide_mail %> <%= mail_to @user.mail unless @user.pref.hide_mail %>
<ul> <ul>
<li><%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %></li> <li><%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %></li>
<% for custom_value in @custom_values %> <% for custom_value in @custom_values %>
<% if !custom_value.value.empty? %> <% if !custom_value.value.empty? %>
<li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li> <li><%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %></li>
<% end %> <% end %>
<% end %> <% end %>
</ul> </ul>
</p> </p>
<h3><%=l(:label_project_plural)%></h3> <h3><%=l(:label_project_plural)%></h3>
<p> <p>
<% for membership in @user.memberships %> <% for membership in @user.memberships %>
<%= membership.project.name %> (<%= membership.role.name %>, <%= format_date(membership.created_on) %>) <%= membership.project.name %> (<%= membership.role.name %>, <%= format_date(membership.created_on) %>)
<br /> <br />
<% end %> <% end %>
</p> </p>
<h3><%=l(:label_activity)%></h3> <h3><%=l(:label_activity)%></h3>
<p> <p>
<%=l(:label_reported_issues)%>: <%= Issue.count(["author_id=?", @user.id]) %> <%=l(:label_reported_issues)%>: <%= Issue.count(["author_id=?", @user.id]) %>
</p> </p>
-25
View File
@@ -1,25 +0,0 @@
<div id="menuAdmin" class="menu" onmouseover="menuMouseover(event)">
<a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuProjects');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_project_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
<a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuUsers');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_user_plural)%></span><span class="menuItemArrow">&#9654;</span></a>
<%= link_to l(:label_role_and_permissions), {:controller => 'roles' }, :class => "menuItem" %>
<a class="menuItem" href="#" onmouseover="menuItemMouseover(event,'menuTrackers');" onclick="this.blur(); return false;"><span class="menuItemText"><%=l(:label_issue_tracking)%></span><span class="menuItemArrow">&#9654;</span></a>
<%= link_to l(:label_custom_field_plural), {:controller => 'custom_fields' }, :class => "menuItem" %>
<%= link_to l(:label_enumerations), {:controller => 'enumerations' }, :class => "menuItem" %>
<%= link_to l(:field_mail_notification), {:controller => 'admin', :action => 'mail_options' }, :class => "menuItem" %>
<%= link_to l(:label_authentication), {:controller => 'auth_sources' }, :class => "menuItem" %>
<%= link_to l(:label_settings), {:controller => 'settings' }, :class => "menuItem" %>
<%= link_to l(:label_information_plural), {:controller => 'admin', :action => 'info' }, :class => "menuItem" %>
</div>
<div id="menuTrackers" class="menu">
<%= link_to l(:label_tracker_plural), {:controller => 'trackers' }, :class => "menuItem" %>
<%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses' }, :class => "menuItem" %>
<%= link_to l(:label_workflow), {:controller => 'roles', :action => 'workflow' }, :class => "menuItem" %>
</div>
<div id="menuProjects" class="menu">
<%= link_to l(:button_list), {:controller => 'admin', :action => 'projects' }, :class => "menuItem" %>
<%= link_to l(:label_new), {:controller => 'projects', :action => 'add' }, :class => "menuItem" %>
</div>
<div id="menuUsers" class="menu">
<%= link_to l(:button_list), {:controller => 'users' }, :class => "menuItem" %>
<%= link_to l(:label_new), {:controller => 'users', :action => 'add' }, :class => "menuItem" %>
</div>
+44 -44
View File
@@ -1,45 +1,45 @@
<h2><%=l(:label_administration)%></h2> <h2><%=l(:label_administration)%></h2>
<p class="icon22 icon22-projects"> <p class="icon22 icon22-projects">
<%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> | <%= link_to l(:label_project_plural), :controller => 'admin', :action => 'projects' %> |
<%= link_to l(:label_new), :controller => 'projects', :action => 'add' %> <%= link_to l(:label_new), :controller => 'projects', :action => 'add' %>
</p> </p>
<p class="icon22 icon22-users"> <p class="icon22 icon22-users">
<%= link_to l(:label_user_plural), :controller => 'users' %> | <%= link_to l(:label_user_plural), :controller => 'users' %> |
<%= link_to l(:label_new), :controller => 'users', :action => 'add' %> <%= link_to l(:label_new), :controller => 'users', :action => 'add' %>
</p> </p>
<p class="icon22 icon22-role"> <p class="icon22 icon22-role">
<%= link_to l(:label_role_and_permissions), :controller => 'roles' %> <%= link_to l(:label_role_and_permissions), :controller => 'roles' %>
</p> </p>
<p class="icon22 icon22-tracker"> <p class="icon22 icon22-tracker">
<%= link_to l(:label_tracker_plural), :controller => 'trackers' %> | <%= link_to l(:label_tracker_plural), :controller => 'trackers' %> |
<%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> | <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> |
<%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %> <%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %>
</p> </p>
<p class="icon22 icon22-workflow"> <p class="icon22 icon22-workflow">
<%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %> <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields' %>
</p> </p>
<p class="icon22 icon22-options"> <p class="icon22 icon22-options">
<%= link_to l(:label_enumerations), :controller => 'enumerations' %> <%= link_to l(:label_enumerations), :controller => 'enumerations' %>
</p> </p>
<p class="icon22 icon22-notifications"> <p class="icon22 icon22-notifications">
<%= link_to l(:field_mail_notification), :controller => 'admin', :action => 'mail_options' %> <%= link_to l(:field_mail_notification), :controller => 'admin', :action => 'mail_options' %>
</p> </p>
<p class="icon22 icon22-authent"> <p class="icon22 icon22-authent">
<%= link_to l(:label_authentication), :controller => 'auth_sources' %> <%= link_to l(:label_authentication), :controller => 'auth_sources' %>
</p> </p>
<p class="icon22 icon22-settings"> <p class="icon22 icon22-settings">
<%= link_to l(:label_settings), :controller => 'settings' %> <%= link_to l(:label_settings), :controller => 'settings' %>
</p> </p>
<p class="icon22 icon22-info"> <p class="icon22 icon22-info">
<%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %> <%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %>
</p> </p>
+3 -9
View File
@@ -1,9 +1,3 @@
<h2><%=l(:label_information_plural)%></h2> <h2><%=l(:label_information_plural)%></h2>
<p><%=l(:field_version)%>: <strong>redMine <%= Redmine::VERSION %></strong> (<%= @db_adapter_name %>)</p> <p><%=l(:field_version)%>: <strong>redMine <%= Redmine::VERSION %></strong></p>
<table class="list">
<tr class="odd"><td>File repository writable</td><td><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
<tr class="even"><td>Default administrator account changed</td><td><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
<tr class="odd"><td>Textile available</td><td><%= image_tag (@flags[:textile_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr>
</table>
+24 -25
View File
@@ -1,25 +1,24 @@
<h2><%=l(:field_mail_notification)%></h2> <h2><%=l(:field_mail_notification)%></h2>
<% form_tag({:action => 'mail_options'}, :id => 'mail_options_form') do %> <% form_tag ({:action => 'mail_options'}, :id => 'mail_options_form') do %>
<div class="box"> <div class="box">
<p><%=l(:text_select_mail_notifications)%></p> <p><%=l(:text_select_mail_notifications)%></p>
<% actions = @actions.group_by {|p| p.group_id } %> <% actions = @actions.group_by {|p| p.group_id } %>
<% actions.keys.sort.each do |group_id| %> <% actions.keys.sort.each do |group_id| %>
<fieldset style="margin-top: 6px;"><legend><strong><%= l(Permission::GROUPS[group_id]) %></strong></legend> <fieldset style="margin-top: 6px;"><legend><strong><%= l(Permission::GROUPS[group_id]) %></strong></legend>
<% actions[group_id].each do |p| %> <% actions[group_id].each do |p| %>
<div style="width:170px;float:left;"><%= check_box_tag "action_ids[]", p.id, p.mail_enabled? %> <div style="width:170px;float:left;"><%= check_box_tag "action_ids[]", p.id, p.mail_enabled? %>
<%= l(p.description.to_sym) %> <%= l(p.description.to_sym) %>
</div> </div>
<% end %> <% end %>
<div class="clear"></div> </fieldset>
</fieldset> <% end %>
<% end %>
<br />
<br /> <p><%= check_all_links 'mail_options_form' %></p>
<p><%= check_all_links('mail_options_form') %></p> </div>
</div>
<%= submit_tag l(:button_save) %>
<%= submit_tag l(:button_save) %> <% end %>
<% end %>
+11 -11
View File
@@ -6,24 +6,24 @@
<table class="list"> <table class="list">
<thead><tr> <thead><tr>
<%= sort_header_tag('name', :caption => l(:label_project)) %> <%= sort_header_tag('name', :caption => l(:label_project)) %>
<th><%=l(:field_description)%></th> <th><%=l(:field_description)%></th>
<th><%=l(:field_is_public)%></th> <th><%=l(:field_is_public)%></th>
<th><%=l(:label_subproject_plural)%></th> <th><%=l(:label_subproject_plural)%></th>
<%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %>
<th></th> <th></th>
</tr></thead> </tr></thead>
<tbody> <tbody>
<% for project in @projects %> <% for project in @projects %>
<tr class="<%= cycle("odd", "even") %>"> <tr class="<%= cycle("odd", "even") %>">
<td><%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %> <td><%= link_to project.name, :controller => 'projects', :action => 'settings', :id => project %>
<td><%=h project.description %> <td><%=h project.description %>
<td align="center"><%= image_tag 'true.png' if project.is_public? %> <td align="center"><%= image_tag 'true.png' if project.is_public? %>
<td align="center"><%= project.children.size %> <td align="center"><%= project.children.size %>
<td align="center"><%= format_date(project.created_on) %> <td align="center"><%= format_date(project.created_on) %>
<td align="center"> <td align="center">
<%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %> <%= button_to l(:button_delete), { :controller => 'projects', :action => 'destroy', :id => project }, :class => "button-small" %>
</td> </td>
</tr> </tr>
<% end %> <% end %>
</tbody> </tbody>
+4 -4
View File
@@ -1,4 +1,4 @@
<h2>404</h2> <h2>404</h2>
<p><%= l(:notice_file_not_found) %></p> <p><%= l(:notice_file_not_found) %></p>
<p><a href="javascript:history.back()">Back</a></p> <p><a href="javascript:history.back()">Back</a></p>
+8 -8
View File
@@ -57,30 +57,30 @@ function deleteValueField(e) {
<!--[form:custom_field]--> <!--[form:custom_field]-->
<div class="box"> <div class="box">
<p><%= f.text_field :name, :required => true %></p> <p><%= f.text_field :name, :required => true %></p>
<p><%= f.select :field_format, custom_field_formats_for_select, {}, :onchange => "toggle_custom_field_format();" %></p> <p><%= f.select :field_format, custom_field_formats_for_select, {}, :onchange => "toggle_custom_field_format();" %></p>
<p><label for="custom_field_min_length"><%=l(:label_min_max_length)%></label> <p><label for="custom_field_min_length"><%=l(:label_min_max_length)%></label>
<%= f.text_field :min_length, :size => 5, :no_label => true %> - <%= f.text_field :min_length, :size => 5, :no_label => true %> -
<%= f.text_field :max_length, :size => 5, :no_label => true %><br>(<%=l(:text_min_max_length_info)%>)</p> <%= f.text_field :max_length, :size => 5, :no_label => true %><br>(<%=l(:text_min_max_length_info)%>)</p>
<p><%= f.text_field :regexp, :size => 50 %><br>(<%=l(:text_regexp_info)%>)</p> <p><%= f.text_field :regexp, :size => 50 %><br>(<%=l(:text_regexp_info)%>)</p>
<p id="custom_field_possible_values"><label><%= l(:field_possible_values) %> <%= image_to_function "add.png", "addValueField();return false" %></label> <p id="custom_field_possible_values"><label><%= l(:field_possible_values) %> <%= image_to_function "add.png", "addValueField();return false" %></label>
<% (@custom_field.possible_values.to_a + [""]).each do |value| %> <% (@custom_field.possible_values.to_a + [""]).each do |value| %>
<span><%= text_field_tag 'custom_field[possible_values][]', value, :size => 30 %> <%= image_to_function "delete.png", "deleteValueField(this);return false" %><br /></span> <span><%= text_field_tag 'custom_field[possible_values][]', value, :size => 30 %> <%= image_to_function "delete.png", "deleteValueField(this);return false" %><br /></span>
<% end %> <% end %>
</p> </p>
</div> </div>
<%= javascript_tag "toggle_custom_field_format();" %> <%= javascript_tag "toggle_custom_field_format();" %>
<!--[eoform:custom_field]--> <!--[eoform:custom_field]-->
<div class="box"> <div class="box">
<% case @custom_field.type.to_s <% case @custom_field.type.to_s
when "IssueCustomField" %> when "IssueCustomField" %>
<fieldset><legend><%=l(:label_tracker_plural)%></legend> <fieldset><legend><%=l(:label_tracker_plural)%></legend>
<% for tracker in @trackers %> <% for tracker in @trackers %>
<%= check_box_tag "tracker_ids[]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %> <%= check_box_tag "tracker_ids[]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %>
<% end %> <% end %>
</fieldset> </fieldset>
&nbsp; &nbsp;
<p><%= f.check_box :is_required %></p> <p><%= f.check_box :is_required %></p>
<p><%= f.check_box :is_for_all %></p> <p><%= f.check_box :is_for_all %></p>
+12 -12
View File
@@ -6,29 +6,29 @@
<li><%= link_to l(:label_project_plural), {}, :id=> "tab-ProjectCustomField", :onclick => "showTab('ProjectCustomField'); this.blur(); return false;" %></li> <li><%= link_to l(:label_project_plural), {}, :id=> "tab-ProjectCustomField", :onclick => "showTab('ProjectCustomField'); this.blur(); return false;" %></li>
<li><%= link_to l(:label_user_plural), {}, :id=> "tab-UserCustomField", :onclick => "showTab('UserCustomField'); this.blur(); return false;" %></li> <li><%= link_to l(:label_user_plural), {}, :id=> "tab-UserCustomField", :onclick => "showTab('UserCustomField'); this.blur(); return false;" %></li>
</ul> </ul>
</div> </div>
<% %w(IssueCustomField ProjectCustomField UserCustomField).each do |type| %> <% %w(IssueCustomField ProjectCustomField UserCustomField).each do |type| %>
<div id="tab-content-<%= type %>" class="tab-content"> <div id="tab-content-<%= type %>" class="tab-content">
<table class="list"> <table class="list">
<thead><tr> <thead><tr>
<th width="30%"><%=l(:field_name)%></th> <th width="30%"><%=l(:field_name)%></th>
<th><%=l(:field_field_format)%></th> <th><%=l(:field_field_format)%></th>
<th><%=l(:field_is_required)%></th> <th><%=l(:field_is_required)%></th>
<% if type == 'IssueCustomField' %> <% if type == 'IssueCustomField' %>
<th><%=l(:field_is_for_all)%></th> <th><%=l(:field_is_for_all)%></th>
<th><%=l(:label_used_by)%></th> <th><%=l(:label_used_by)%></th>
<% end %> <% end %>
<th width="10%"></th> <th width="10%"></th>
</tr></thead> </tr></thead>
<tbody> <tbody>
<% for custom_field in (@custom_fields_by_type[type] || []) %> <% for custom_field in (@custom_fields_by_type[type] || []) %>
<tr class="<%= cycle("odd", "even") %>"> <tr class="<%= cycle("odd", "even") %>">
<td><%= link_to custom_field.name, :action => 'edit', :id => custom_field %></td> <td><%= link_to custom_field.name, :action => 'edit', :id => custom_field %></td>
<td align="center"><%= l(CustomField::FIELD_FORMATS[custom_field.field_format][:name]) %></td> <td align="center"><%= l(CustomField::FIELD_FORMATS[custom_field.field_format][:name]) %></td>
<td align="center"><%= image_tag 'true.png' if custom_field.is_required? %></td> <td align="center"><%= image_tag 'true.png' if custom_field.is_required? %></td>
<% if type == 'IssueCustomField' %> <% if type == 'IssueCustomField' %>
<td align="center"><%= image_tag 'true.png' if custom_field.is_for_all? %></td> <td align="center"><%= image_tag 'true.png' if 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"><%= 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>
<% end %> <% end %>
<td align="center"> <td align="center">
+2 -2
View File
@@ -1,3 +1,3 @@
<p><%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %><br /> <p><%= link_to h(document.title), :controller => 'documents', :action => 'show', :id => document %><br />
<% unless document.description.empty? %><%=h(truncate(document.description, 250)) %><br /><% end %> <% unless document.description.empty? %><%=h(truncate(document.description, 250)) %><br /><% end %>
<em><%= format_time(document.created_on) %></em></p> <em><%= format_time(document.created_on) %></em></p>
+5 -5
View File
@@ -1,16 +1,16 @@
<%= error_messages_for 'document' %> <%= error_messages_for 'document' %>
<div class="box"> <div class="box">
<!--[form:document]--> <!--[form:document]-->
<p><label for="document_category_id"><%=l(:field_category)%></label> <p><label for="document_category_id"><%=l(:field_category)%></label>
<select name="document[category_id]"> <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> </select></p>
<p><label for="document_title"><%=l(:field_title)%> <span class="required">*</span></label> <p><label for="document_title"><%=l(:field_title)%> <span class="required">*</span></label>
<%= text_field 'document', 'title', :size => 60 %></p> <%= text_field 'document', 'title', :size => 60 %></p>
<p><label for="document_description"><%=l(:field_description)%></label> <p><label for="document_description"><%=l(:field_description)%></label>
<%= text_area 'document', 'description', :cols => 60, :rows => 15, :class => 'wiki-edit' %></p> <%= text_area 'document', 'description', :cols => 60, :rows => 15 %></p>
<!--[eoform:document]--> <!--[eoform:document]-->
</div> </div>
+33 -34
View File
@@ -1,38 +1,37 @@
<div class="contextual"> <div class="contextual">
<%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit' %> <%= link_to_if_authorized l(:button_edit), {:controller => 'documents', :action => 'edit', :id => @document}, :class => 'icon icon-edit' %>
<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> <%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy', :id => @document}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
</div> </div>
<h2><%= @document.title %></h2> <h2><%= @document.title %></h2>
<p><em><%= @document.category.name %><br /> <p><em><%= @document.category.name %><br />
<%= format_date @document.created_on %></em></p> <%= format_date @document.created_on %></em></p>
<%= textilizable @document.description %> <%= textilizable @document.description %>
<br /> <br />
<h3><%= l(:label_attachment_plural) %></h3> <h3><%= l(:label_attachment_plural) %></h3>
<ul class="documents"> <ul class="documents">
<% for attachment in @attachments %> <% for attachment in @attachments %>
<li> <li>
<div class="contextual"> <div class="contextual">
<%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy_attachment', :id => @document, :attachment_id => attachment}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> <%= link_to_if_authorized l(:button_delete), {:controller => 'documents', :action => 'destroy_attachment', :id => @document, :attachment_id => attachment}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
</div> </div>
<%= link_to attachment.filename, :action => 'download', :id => @document, :attachment_id => attachment %> <%= link_to attachment.filename, :action => 'download', :id => @document, :attachment_id => attachment %>
(<%= number_to_human_size attachment.filesize %>)<br /> (<%= number_to_human_size attachment.filesize %>)<br />
<em><%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %></em><br /> <em><%= attachment.author.display_name %>, <%= format_date(attachment.created_on) %></em><br />
<%= lwr(:label_download, attachment.downloads) %> <%= lwr(:label_download, attachment.downloads) %>
</li> </li>
<% end %>
</ul>
<br />
<% if authorize_for('documents', 'add_attachment') %>
<p><%= toggle_link l(:label_attachment_new), "add_attachment_form" %></p>
<% form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :class => "tabular", :id => "add_attachment_form", :style => "display:none;") do %>
<p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%>
<%= image_to_function "add.png", "addFileField();return false" %></label>
<%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p>
<%= submit_tag l(:button_add) %>
<% end %>
<% end %> <% end %>
</ul>
<br />
<% if authorize_for('documents', 'add_attachment') %>
<% form_tag ({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :class => "tabular") do %>
<p id="attachments_p"><label for="attachment_file"><%=l(:label_attachment)%>
<%= image_to_function "add.png", "addFileField();return false" %></label>
<%= file_field_tag 'attachments[]', :size => 30 %> <em>(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>)</em></p>
<%= submit_tag l(:button_add) %>
<% end %>
<% end %>
+16 -16
View File
@@ -1,19 +1,19 @@
<h2><%=l(:label_enumerations)%></h2> <h2><%=l(:label_enumerations)%></h2>
&nbsp; &nbsp;
<% Enumeration::OPTIONS.each do |option, name| %> <% Enumeration::OPTIONS.each do |option, name| %>
<% if params[:opt]==option %> <% if params[:opt]==option %>
<h3><%= l(name) %></h3> <h3><%= l(name) %></h3>
<ul> <ul>
<% for value in Enumeration.find(:all, :conditions => ["opt = ?", option]) %> <% for value in Enumeration.find(:all, :conditions => ["opt = ?", option]) %>
<li><%= link_to value.name, :action => 'edit', :id => value %></li> <li><%= link_to value.name, :action => 'edit', :id => value %></li>
<% end %> <% end %>
</ul> </ul>
<p><%= link_to l(:label_enumeration_new), { :action => 'new', :opt => option }, :class => "icon icon-add" %></p>&nbsp; <p><%= link_to l(:label_enumeration_new), { :action => 'new', :opt => option }, :class => "icon icon-add" %></p>&nbsp;
<% else %> <% else %>
<h3><%= link_to l(name), :opt => option %></h3> <h3><%= link_to l(name), :opt => option %></h3>
<% end %> <% end %>
<% end %> <% end %>
Loaded 100 of 363 files, more files were not shown because too many files have changed in this diff. Show more