pax_global_header 0000666 0000000 0000000 00000000064 11615721634 0014520 g ustar 00root root 0000000 0000000 52 comment=aa2c444acf5e8a79db5875d9167ed2dbedd424bd ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/ 0000775 0000000 0000000 00000000000 11615721634 0021413 5 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/.gitignore 0000664 0000000 0000000 00000000571 11615721634 0023406 0 ustar 00root root 0000000 0000000 /.project /.loadpath /config/additional_environment.rb /config/configuration.yml /config/database.yml /config/email.yml /config/initializers/session_store.rb /coverage /db/*.db /db/*.sqlite3 /db/schema.rb /files/* /log/*.log* /log/mongrel_debug /public/dispatch.* /public/plugin_assets /tmp/* /tmp/cache/* /tmp/sessions/* /tmp/sockets/* /tmp/test/* /vendor/rails *.rbc doc/app ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/.gitmodules 0000664 0000000 0000000 00000000422 11615721634 0023566 0 ustar 00root root 0000000 0000000 [submodule "vendor/plugins/redmine_bots_filter"] path = vendor/plugins/redmine_bots_filter url = git://github.com/edavis10/redmine_bots_filter.git [submodule "vendor/plugins/redmine_scm"] path = vendor/plugins/redmine_scm url = git://github.com/splendeo/redmine_scm.git ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/.hgignore 0000664 0000000 0000000 00000000551 11615721634 0023217 0 ustar 00root root 0000000 0000000 syntax: glob .project .loadpath config/additional_environment.rb config/configuration.yml config/database.yml config/email.yml config/initializers/session_store.rb coverage db/*.db db/*.sqlite3 db/schema.rb files/* log/*.log* log/mongrel_debug public/dispatch.* public/plugin_assets tmp/* tmp/cache/* tmp/sessions/* tmp/sockets/* tmp/test/* vendor/rails *.rbc ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/README.rdoc 0000664 0000000 0000000 00000003376 11615721634 0023232 0 ustar 00root root 0000000 0000000 = ChiliProject ChiliProject is a web based project management system. It supports your team throughout the complete project life cycle, from setting up and discussing a project plan, over tracking issues and reporting work progress to collaboratively sharing knowledge. More documentation and user guides can be found on the official website[https://www.chiliproject.org] and in the doc/ directory. == Getting Started We have a complete {install guide}[https://www.chiliproject.org/projects/chiliproject/wiki/Installation] online. == Getting Help ChiliProject is an run by a community of volunteers. We have set up different ways to get help depending on your preferences. * Self guided help and user documentation - https://www.chiliproject.org/projects/chiliproject/wiki/Help * Forums for specific questions - https://www.chiliproject.org/projects/chiliproject/boards * Real time chat using IRC - https://www.chiliproject.org/projects/chiliproject/wiki/IRC * Commercial support - https://www.chiliproject.org/projects/chiliproject/wiki/Commercial_Offerings == Contributing We welcome all help for the project, no task is too small. Our documentation is editable by anyone on our wiki[https://www.chiliproject.org/projects/chiliproject/wiki], we accept patches on our {issue tracker}[https://www.chiliproject.org/projects/chiliproject/issues], and everyone is welcome to discuss the project in our forums[https://www.chiliproject.org/projects/chiliproject/boards]. More details can be found on our Contribute page[https://www.chiliproject.org/projects/chiliproject/wiki/Contribute]. == License ChiliProject is licensed under the GNU GPL v2. See the doc directory for more details. ChiliProject is a fork based on Redmine. Redmine is Copyright Jean-Philippe Lang and others. ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/Rakefile 0000664 0000000 0000000 00000000463 11615721634 0023063 0 ustar 00root root 0000000 0000000 # Add your own tasks in files placed in lib/tasks ending in .rake, # for example lib/tasks/switchtower.rake, and they will automatically be available to Rake. require(File.join(File.dirname(__FILE__), 'config', 'boot')) require 'rake' require 'rake/testtask' require 'rake/rdoctask' require 'tasks/rails' ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/ 0000775 0000000 0000000 00000000000 11615721634 0022173 5 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/ 0000775 0000000 0000000 00000000000 11615721634 0024541 5 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/account_controller.rb 0000664 0000000 0000000 00000022173 11615721634 0030772 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class AccountController < ApplicationController helper :custom_fields include CustomFieldsHelper # prevents login action to be filtered by check_if_login_required application scope filter skip_before_filter :check_if_login_required # Login request and validation def login if request.get? logout_user else authenticate_user end end # Log out current user and redirect to welcome page def logout logout_user redirect_to home_url end # Enable user to choose a new password def lost_password redirect_to(home_url) && return unless Setting.lost_password? if params[:token] @token = Token.find_by_action_and_value("recovery", params[:token]) redirect_to(home_url) && return unless @token and !@token.expired? @user = @token.user if request.post? @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] if @user.save @token.destroy flash[:notice] = l(:notice_account_password_updated) redirect_to :action => 'login' return end end render :template => "account/password_recovery" return else if request.post? user = User.find_by_mail(params[:mail]) # user not found in db (flash.now[:error] = l(:notice_account_unknown_email); return) unless user # user uses an external authentification (flash.now[:error] = l(:notice_can_t_change_password); return) if user.auth_source_id # create a new token for password recovery token = Token.new(:user => user, :action => "recovery") if token.save Mailer.deliver_lost_password(token) flash[:notice] = l(:notice_account_lost_email_sent) redirect_to :action => 'login', :back_url => home_url return end end end end # User self-registration def register redirect_to(home_url) && return unless Setting.self_registration? || session[:auth_source_registration] if request.get? session[:auth_source_registration] = nil @user = User.new(:language => Setting.default_language) else @user = User.new(params[:user]) @user.admin = false @user.register if session[:auth_source_registration] @user.activate @user.login = session[:auth_source_registration][:login] @user.auth_source_id = session[:auth_source_registration][:auth_source_id] if @user.save session[:auth_source_registration] = nil self.logged_user = @user flash[:notice] = l(:notice_account_activated) redirect_to :controller => 'my', :action => 'account' end else @user.login = params[:user][:login] @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] case Setting.self_registration when '1' register_by_email_activation(@user) when '3' register_automatically(@user) else register_manually_by_administrator(@user) end end end end # Token based account activation def activate redirect_to(home_url) && return unless Setting.self_registration? && params[:token] token = Token.find_by_action_and_value('register', params[:token]) redirect_to(home_url) && return unless token and !token.expired? user = token.user redirect_to(home_url) && return unless user.registered? user.activate if user.save token.destroy flash[:notice] = l(:notice_account_activated) end redirect_to :action => 'login' end private def logout_user if User.current.logged? cookies.delete Redmine::Configuration['autologin_cookie_name'] Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) self.logged_user = nil end end def authenticate_user if Setting.openid? && using_open_id? open_id_authenticate(params[:openid_url]) else password_authentication end end def password_authentication user = User.try_to_login(params[:username], params[:password]) if user.nil? invalid_credentials elsif user.new_record? onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id }) else # Valid user successful_authentication(user) end end def open_id_authenticate(openid_url) authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration| if result.successful? user = User.find_or_initialize_by_identity_url(identity_url) if user.new_record? # Self-registration off redirect_to(home_url) && return unless Setting.self_registration? # Create on the fly user.login = registration['nickname'] unless registration['nickname'].nil? user.mail = registration['email'] unless registration['email'].nil? user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? user.random_password user.register case Setting.self_registration when '1' register_by_email_activation(user) do onthefly_creation_failed(user) end when '3' register_automatically(user) do onthefly_creation_failed(user) end else register_manually_by_administrator(user) do onthefly_creation_failed(user) end end else # Existing record if user.active? successful_authentication(user) else account_pending end end end end end def successful_authentication(user) # Valid user self.logged_user = user # generate a key and set cookie if autologin if params[:autologin] && Setting.autologin? set_autologin_cookie(user) end call_hook(:controller_account_success_authentication_after, {:user => user }) redirect_back_or_default :controller => 'my', :action => 'page' end def set_autologin_cookie(user) token = Token.create(:user => user, :action => 'autologin') cookie_options = { :value => token.value, :expires => 1.year.from_now, :path => Redmine::Configuration['autologin_cookie_path'], :secure => Redmine::Configuration['autologin_cookie_secure'], :httponly => true } cookies[Redmine::Configuration['autologin_cookie_name']] = cookie_options end # Onthefly creation failed, display the registration form to fill/fix attributes def onthefly_creation_failed(user, auth_source_options = { }) @user = user session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? render :action => 'register' end def invalid_credentials logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}" flash.now[:error] = l(:notice_account_invalid_creditentials) end # Register a user for email activation. # # Pass a block for behavior when a user fails to save def register_by_email_activation(user, &block) token = Token.new(:user => user, :action => "register") if user.save and token.save Mailer.deliver_register(token) flash[:notice] = l(:notice_account_register_done) redirect_to :action => 'login' else yield if block_given? end end # Automatically register a user # # Pass a block for behavior when a user fails to save def register_automatically(user, &block) # Automatic activation user.activate user.last_login_on = Time.now if user.save self.logged_user = user flash[:notice] = l(:notice_account_activated) redirect_to :controller => 'my', :action => 'account' else yield if block_given? end end # Manual activation by the administrator # # Pass a block for behavior when a user fails to save def register_manually_by_administrator(user, &block) if user.save # Sends an email to the administrators Mailer.deliver_account_activation_request(user) account_pending else yield if block_given? end end def account_pending flash[:notice] = l(:notice_account_pending) redirect_to :action => 'login' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/activities_controller.rb 0000664 0000000 0000000 00000003765 11615721634 0031510 0 ustar 00root root 0000000 0000000 class ActivitiesController < ApplicationController menu_item :activity before_filter :find_optional_project accept_key_auth :index def index @days = Setting.activity_days_default.to_i if params[:from] begin; @date_to = params[:from].to_date + 1; rescue; end end @date_to ||= Date.today + 1 @date_from = @date_to - @days @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, :with_subprojects => @with_subprojects, :author => @author) @activity.scope_select {|t| !params["show_#{t}"].nil?} @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? events = @activity.events(@date_from, @date_to) if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, User.current, current_language]) respond_to do |format| format.html { @events_by_day = events.group_by(&:event_date) render :layout => false if request.xhr? } format.atom { title = l(:label_activity) if @author title = @author.name elsif @activity.scope.size == 1 title = l("label_#{@activity.scope.first.singularize}_plural") end render_feed(events, :title => "#{@project || Setting.app_title}: #{title}") } end end rescue ActiveRecord::RecordNotFound render_404 end private # TODO: refactor, duplicated in projects_controller def find_optional_project return true unless params[:id] @project = Project.find(params[:id]) authorize rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/admin_controller.rb 0000664 0000000 0000000 00000006040 11615721634 0030421 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class AdminController < ApplicationController layout 'admin' before_filter :require_admin helper :sort include SortHelper def index @no_configuration_data = Redmine::DefaultData::Loader::no_data? end def projects @status = params[:status] ? params[:status].to_i : 1 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) unless params[:name].blank? name = "%#{params[:name].strip.downcase}%" c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name] end @projects = Project.find :all, :order => 'lft', :conditions => c.conditions render :action => "projects", :layout => false if request.xhr? end def plugins @plugins = Redmine::Plugin.all end # Loads the default configuration # (roles, trackers, statuses, workflow, enumerations) def default_configuration if request.post? begin Redmine::DefaultData::Loader::load(params[:lang]) flash[:notice] = l(:notice_default_data_loaded) rescue Exception => e flash[:error] = l(:error_can_t_load_default_data, e.message) end end redirect_to :action => 'index' end def test_email raise_delivery_errors = ActionMailer::Base.raise_delivery_errors # Force ActionMailer to raise delivery errors so we can catch it ActionMailer::Base.raise_delivery_errors = true begin @test = Mailer.deliver_test(User.current) flash[:notice] = l(:notice_email_sent, User.current.mail) rescue Exception => e flash[:error] = l(:notice_email_error, e.message) end ActionMailer::Base.raise_delivery_errors = raise_delivery_errors redirect_to :controller => 'settings', :action => 'edit', :tab => 'notifications' end def info @db_adapter_name = ActiveRecord::Base.connection.adapter_name @checklist = [ [:text_default_administrator_account_changed, User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?], [:text_file_repository_writable, File.writable?(Attachment.storage_path)], [:text_plugin_assets_writable, File.writable?(Engines.public_directory)], [:text_rmagick_available, Object.const_defined?(:Magick)] ] end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/application_controller.rb 0000664 0000000 0000000 00000036611 11615721634 0031643 0 ustar 00root root 0000000 0000000 # 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 'uri' require 'cgi' class ApplicationController < ActionController::Base protected include Redmine::I18n layout 'base' exempt_from_layout 'builder', 'rsb' protect_from_forgery def handle_unverified_request super cookies.delete(:autologin) end # Remove broken cookie after upgrade from 0.8.x (#4292) # See https://rails.lighthouseapp.com/projects/8994/tickets/3360 # TODO: remove it when Rails is fixed before_filter :delete_broken_cookies def delete_broken_cookies if cookies['_chiliproject_session'] && cookies['_chiliproject_session'] !~ /--/ cookies.delete '_chiliproject_session' redirect_to home_path return false end end before_filter :user_setup, :check_if_login_required, :set_localization filter_parameter_logging :password rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token include Redmine::Search::Controller include Redmine::MenuManager::MenuController helper Redmine::MenuManager::MenuHelper Redmine::Scm::Base.all.each do |scm| require_dependency "repository/#{scm.underscore}" end def user_setup # Check the settings cache for each request Setting.check_cache # Find the current user User.current = find_current_user end # Returns the current user or nil if no user is logged in # and starts a session if needed def find_current_user if session[:user_id] # existing session (User.active.find(session[:user_id]) rescue nil) elsif cookies[Redmine::Configuration['autologin_cookie_name']] && Setting.autologin? # auto-login feature starts a new session user = User.try_to_autologin(cookies[Redmine::Configuration['autologin_cookie_name']]) session[:user_id] = user.id if user user elsif params[:format] == 'atom' && params[:key] && accept_key_auth_actions.include?(params[:action]) # RSS key authentication does not start a session User.find_by_rss_key(params[:key]) elsif Setting.rest_api_enabled? && api_request? if (key = api_key_from_request) && accept_key_auth_actions.include?(params[:action]) # Use API key User.find_by_api_key(key) else # HTTP Basic, either username/password or API key/random authenticate_with_http_basic do |username, password| User.try_to_login(username, password) || User.find_by_api_key(username) end end end end # Sets the logged in user def logged_user=(user) reset_session if user && user.is_a?(User) User.current = user session[:user_id] = user.id else User.current = User.anonymous end end # check if login is globally required to access the application def check_if_login_required # no check needed if user is already logged in return true if User.current.logged? require_login if Setting.login_required? end def set_localization lang = nil if User.current.logged? lang = find_language(User.current.language) end if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE'] accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first if !accept_lang.blank? accept_lang = accept_lang.downcase lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) end end lang ||= Setting.default_language set_language_if_valid(lang) end def require_login if !User.current.logged? # Extract only the basic url parameters on non-GET requests if request.get? url = url_for(params) else url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id]) end respond_to do |format| format.html { redirect_to :controller => "account", :action => "login", :back_url => url } format.atom { redirect_to :controller => "account", :action => "login", :back_url => url } format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="ChiliProject API"' } format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="ChiliProject API"' } format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="ChiliProject API"' } end return false end true end def require_admin return unless require_login if !User.current.admin? render_403 return false end true end def deny_access User.current.logged? ? render_403 : require_login end # Authorize the user for the requested action def authorize(ctrl = params[:controller], action = params[:action], global = false) allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project || @projects, :global => global) if allowed true else if @project && @project.archived? render_403 :message => :notice_not_authorized_archived_project else deny_access end end end # Authorize the user for the requested action outside a project def authorize_global(ctrl = params[:controller], action = params[:action], global = true) authorize(ctrl, action, global) end # Find project of id params[:id] def find_project @project = Project.find(params[:id]) rescue ActiveRecord::RecordNotFound render_404 end # Find project of id params[:project_id] def find_project_by_project_id @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end # Find a project based on params[:project_id] # TODO: some subclasses override this, see about merging their logic def find_optional_project @project = Project.find(params[:project_id]) unless params[:project_id].blank? allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) allowed ? true : deny_access rescue ActiveRecord::RecordNotFound render_404 end # Finds and sets @project based on @object.project def find_project_from_association render_404 unless @object.present? @project = @object.project rescue ActiveRecord::RecordNotFound render_404 end def find_model_object model = self.class.read_inheritable_attribute('model_object') if model @object = model.find(params[:id]) self.instance_variable_set('@' + controller_name.singularize, @object) if @object end rescue ActiveRecord::RecordNotFound render_404 end def self.model_object(model) write_inheritable_attribute('model_object', model) end # Filter for bulk issue operations def find_issues @issues = Issue.find_all_by_id(params[:id] || params[:ids]) raise ActiveRecord::RecordNotFound if @issues.empty? @projects = @issues.collect(&:project).compact.uniq @project = @projects.first if @projects.size == 1 rescue ActiveRecord::RecordNotFound render_404 end # Check if project is unique before bulk operations def check_project_uniqueness unless @project # TODO: let users bulk edit/move/destroy issues from different projects render_error 'Can not bulk edit/move/destroy issues from different projects' return false end 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 if @project && @project.active? if @project.is_public? || User.current.member_of?(@project) || User.current.admin? true else User.current.logged? ? render_403 : require_login end else @project = nil render_404 false end end def back_url params[:back_url] || request.env['HTTP_REFERER'] end def redirect_back_or_default(default) back_url = CGI.unescape(params[:back_url].to_s) if !back_url.blank? begin uri = URI.parse(back_url) # do not redirect user to another host or to the login or register page if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)}) redirect_to(back_url) return end rescue URI::InvalidURIError # redirect to default end end redirect_to default false end def render_403(options={}) @project = nil render_error({:message => :notice_not_authorized, :status => 403}.merge(options)) return false end def render_404(options={}) render_error({:message => :notice_file_not_found, :status => 404}.merge(options)) return false end # Renders an error response def render_error(arg) arg = {:message => arg} unless arg.is_a?(Hash) @message = arg[:message] @message = l(@message) if @message.is_a?(Symbol) @status = arg[:status] || 500 respond_to do |format| format.html { render :template => 'common/error', :layout => use_layout, :status => @status } format.atom { head @status } format.xml { head @status } format.js { head @status } format.json { head @status } end end # Picks which layout to use based on the request # # @return [boolean, string] name of the layout to use or false for no layout def use_layout request.xhr? ? false : 'base' end def invalid_authenticity_token if api_request? logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)." end render_error "Invalid form authenticity token." end def render_feed(items, options={}) @items = items || [] @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } @items = @items.slice(0, Setting.feeds_limit.to_i) @title = options[:title] || Setting.app_title render :template => "common/feed.atom.rxml", :layout => false, :content_type => 'application/atom+xml' end def self.accept_key_auth(*actions) actions = actions.flatten.map(&:to_s) write_inheritable_attribute('accept_key_auth_actions', actions) end def accept_key_auth_actions self.class.read_inheritable_attribute('accept_key_auth_actions') || [] end # Returns the number of objects that should be displayed # on the paginated list def per_page_option per_page = nil if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i) per_page = params[:per_page].to_s.to_i session[:per_page] = per_page elsif session[:per_page] per_page = session[:per_page] else per_page = Setting.per_page_options_array.first || 25 end per_page end # Returns offset and limit used to retrieve objects # for an API response based on offset, limit and page parameters def api_offset_and_limit(options=params) if options[:offset].present? offset = options[:offset].to_i if offset < 0 offset = 0 end end limit = options[:limit].to_i if limit < 1 limit = 25 elsif limit > 100 limit = 100 end if offset.nil? && options[:page].present? offset = (options[:page].to_i - 1) * limit offset = 0 if offset < 0 end offset ||= 0 [offset, limit] end # qvalues http header parser # code taken from webrick def parse_qvalues(value) tmp = [] if value parts = value.split(/,\s*/) parts.each {|part| if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) val = m[1] q = (m[2] or 1).to_f tmp.push([val, q]) end } tmp = tmp.sort_by{|val, q| -q} tmp.collect!{|val, q| val} end return tmp rescue nil end # Returns a string that can be used as filename value in Content-Disposition header def filename_for_content_disposition(name) request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name end def api_request? %w(xml json).include? params[:format] end # Returns the API key present in the request def api_key_from_request if params[:key].present? params[:key] elsif request.headers["X-ChiliProject-API-Key"].present? request.headers["X-ChiliProject-API-Key"] end end # Renders a warning flash if obj has unsaved attachments def render_attachment_warning_if_needed(obj) flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present? end # Sets the `flash` notice or error based the number of issues that did not save # # @param [Array, Issue] issues all of the saved and unsaved Issues # @param [Array, Integer] unsaved_issue_ids the issue ids that were not saved def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) if unsaved_issue_ids.empty? flash[:notice] = l(:notice_successful_update) unless issues.empty? else flash[:error] = l(:notice_failed_to_save_issues, :count => unsaved_issue_ids.size, :total => issues.size, :ids => '#' + unsaved_issue_ids.join(', #')) end end # Rescues an invalid query statement. Just in case... def query_statement_invalid(exception) logger.error "Query::StatementInvalid: #{exception.message}" if logger session.delete(:query) sort_clear if respond_to?(:sort_clear) render_error "An error occurred while executing the query and has been logged. Please report this error to your administrator." end # Converts the errors on an ActiveRecord object into a common JSON format def object_errors_to_json(object) object.errors.collect do |attribute, error| { attribute => error } end.to_json end # Renders API response on validation failure def render_validation_errors(object) options = { :status => :unprocessable_entity, :layout => false } options.merge!(case params[:format] when 'xml'; { :xml => object.errors } when 'json'; { :json => {'errors' => object.errors} } # ActiveResource client compliance else raise "Unknown format #{params[:format]} in #render_validation_errors" end ) render options end # Overrides #default_template so that the api template # is used automatically if it exists def default_template(action_name = self.action_name) if api_request? begin return self.view_paths.find_template(default_template_name(action_name), 'api') rescue ::ActionView::MissingTemplate # the api template was not found # fallback to the default behaviour end end super end # Overrides #pick_layout so that #render with no arguments # doesn't use the layout for api requests def pick_layout(*args) api_request? ? nil : super end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/attachments_controller.rb 0000664 0000000 0000000 00000005646 11615721634 0031657 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2008 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 AttachmentsController < ApplicationController before_filter :find_project before_filter :file_readable, :read_authorize, :except => :destroy before_filter :delete_authorize, :only => :destroy verify :method => :post, :only => :destroy def show if @attachment.is_diff? @diff = File.new(@attachment.diskfile, "rb").read render :action => 'diff' elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte @content = File.new(@attachment.diskfile, "rb").read render :action => 'file' else download end end def download if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) @attachment.increment_download end # images are sent inline send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), :type => detect_content_type(@attachment), :disposition => (@attachment.image? ? 'inline' : 'attachment') end def destroy # Make sure association callbacks are called @attachment.container.attachments.delete(@attachment) redirect_to :back rescue ::ActionController::RedirectBackError redirect_to :controller => 'projects', :action => 'show', :id => @project end private def find_project @attachment = Attachment.find(params[:id]) # Show 404 if the filename in the url is wrong raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename @project = @attachment.project rescue ActiveRecord::RecordNotFound render_404 end # Checks that the file exists and is readable def file_readable @attachment.readable? ? true : render_404 end def read_authorize @attachment.visible? ? true : deny_access end def delete_authorize @attachment.deletable? ? true : deny_access end def detect_content_type(attachment) content_type = attachment.content_type if content_type.blank? content_type = Redmine::MimeType.of(attachment.filename) end content_type.to_s end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/auth_sources_controller.rb 0000664 0000000 0000000 00000004756 11615721634 0032051 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class AuthSourcesController < ApplicationController layout 'admin' before_filter :require_admin # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :template => :index } def index @auth_source_pages, @auth_sources = paginate auth_source_class.name.tableize, :per_page => 10 render "auth_sources/index" end def new @auth_source = auth_source_class.new render 'auth_sources/new' end def create @auth_source = auth_source_class.new(params[:auth_source]) if @auth_source.save flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index' else render 'auth_sources/new' end end def edit @auth_source = AuthSource.find(params[:id]) render 'auth_sources/edit' end def update @auth_source = AuthSource.find(params[:id]) if @auth_source.update_attributes(params[:auth_source]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' else render 'auth_sources/edit' end end def test_connection @auth_method = AuthSource.find(params[:id]) begin @auth_method.test_connection flash[:notice] = l(:notice_successful_connection) rescue => text flash[:error] = l(:error_unable_to_connect, text.message) end redirect_to :action => 'index' end def destroy @auth_source = AuthSource.find(params[:id]) unless @auth_source.users.find(:first) @auth_source.destroy flash[:notice] = l(:notice_successful_delete) end redirect_to :action => 'index' end protected def auth_source_class AuthSource end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/auto_completes_controller.rb 0000664 0000000 0000000 00000001671 11615721634 0032361 0 ustar 00root root 0000000 0000000 class AutoCompletesController < ApplicationController before_filter :find_project def issues @issues = [] q = params[:q].to_s if q.present? query = (params[:scope] == "all" && Setting.cross_project_issue_relations?) ? Issue : @project.issues @issues |= query.visible.find_all_by_id(q.to_i) if q =~ /^\d+$/ @issues |= query.visible.find(:all, :limit => 10, :order => "#{Issue.table_name}.id ASC", :conditions => ["LOWER(#{Issue.table_name}.subject) LIKE :q OR CAST(#{Issue.table_name}.id AS CHAR(13)) LIKE :q", {:q => "%#{q.downcase}%" }]) end render :layout => false end private def find_project project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] @project = Project.find(project_id) rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/boards_controller.rb 0000664 0000000 0000000 00000006707 11615721634 0030615 0 ustar 00root root 0000000 0000000 # 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 BoardsController < ApplicationController default_search_scope :messages before_filter :find_project, :find_board_if_available, :authorize accept_key_auth :index, :show helper :messages include MessagesHelper helper :sort include SortHelper helper :watchers include WatchersHelper def index @boards = @project.boards render_404 if @boards.empty? # show the board if there is only one if @boards.size == 1 @board = @boards.first show end end def show respond_to do |format| format.html { sort_init 'updated_on', 'desc' sort_update 'created_on' => "#{Message.table_name}.created_on", 'replies' => "#{Message.table_name}.replies_count", 'updated_on' => "#{Message.table_name}.updated_on" @topic_count = @board.topics.count @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page'] @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), :include => [:author, {:last_reply => :author}], :limit => @topic_pages.items_per_page, :offset => @topic_pages.current.offset @message = Message.new render :action => 'show', :layout => !request.xhr? } format.atom { @messages = @board.messages.find :all, :order => 'created_on DESC', :include => [:author, :board], :limit => Setting.feeds_limit.to_i render_feed(@messages, :title => "#{@project}: #{@board}") } end end verify :method => :post, :only => [ :destroy ], :redirect_to => { :action => :index } def new @board = Board.new(params[:board]) @board.project = @project if request.post? && @board.save flash[:notice] = l(:notice_successful_create) redirect_to_settings_in_projects end end def edit if request.post? && @board.update_attributes(params[:board]) redirect_to_settings_in_projects end end def destroy @board.destroy redirect_to_settings_in_projects end private def redirect_to_settings_in_projects redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'boards' end def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end def find_board_if_available @board = @project.boards.find(params[:id]) if params[:id] rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/calendars_controller.rb 0000664 0000000 0000000 00000002556 11615721634 0031275 0 ustar 00root root 0000000 0000000 class CalendarsController < ApplicationController menu_item :calendar before_filter :find_optional_project rescue_from Query::StatementInvalid, :with => :query_statement_invalid helper :issues helper :projects helper :queries include QueriesHelper helper :sort include SortHelper def show if params[:year] and params[:year].to_i > 1900 @year = params[:year].to_i if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 @month = params[:month].to_i end end @year ||= Date.today.year @month ||= Date.today.month @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) retrieve_query @query.group_by = nil if @query.valid? events = [] events += @query.issues(:include => [:tracker, :assigned_to, :priority], :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] ) events += @query.versions(:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) @calendar.events = events end render :action => 'show', :layout => false if request.xhr? end def update show end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/comments_controller.rb 0000664 0000000 0000000 00000002074 11615721634 0031161 0 ustar 00root root 0000000 0000000 class CommentsController < ApplicationController default_search_scope :news model_object News before_filter :find_model_object before_filter :find_project_from_association before_filter :authorize verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @comment = Comment.new(params[:comment]) @comment.author = User.current if @news.comments << @comment flash[:notice] = l(:label_comment_added) end redirect_to :controller => 'news', :action => 'show', :id => @news end verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } def destroy @news.comments.find(params[:comment_id]).destroy redirect_to :controller => 'news', :action => 'show', :id => @news end private # ApplicationController's find_model_object sets it based on the controller # name so it needs to be overriden and set to @news instead def find_model_object super @news = @object @comment = nil @news end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/context_menus_controller.rb 0000664 0000000 0000000 00000003467 11615721634 0032236 0 ustar 00root root 0000000 0000000 class ContextMenusController < ApplicationController helper :watchers def issues @issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project) if (@issues.size == 1) @issue = @issues.first @allowed_statuses = @issue.new_statuses_allowed_to(User.current) else @allowed_statuses = @issues.map do |i| i.new_statuses_allowed_to(User.current) end.inject do |memo,s| memo & s end end @projects = @issues.collect(&:project).compact.uniq @project = @projects.first if @projects.size == 1 @can = {:edit => User.current.allowed_to?(:edit_issues, @projects), :log_time => (@project && User.current.allowed_to?(:log_time, @project)), :update => (User.current.allowed_to?(:edit_issues, @projects) || (User.current.allowed_to?(:change_status, @projects) && !@allowed_statuses.blank?)), :move => (@project && User.current.allowed_to?(:move_issues, @project)), :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)), :delete => User.current.allowed_to?(:delete_issues, @projects) } if @project @assignables = @project.assignable_users @assignables << @issue.assigned_to if @issue && @issue.assigned_to && !@assignables.include?(@issue.assigned_to) @trackers = @project.trackers else #when multiple projects, we only keep the intersection of each set @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} end @priorities = IssuePriority.all.reverse @statuses = IssueStatus.find(:all, :order => 'position') @back = back_url render :layout => false end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/custom_fields_controller.rb 0000664 0000000 0000000 00000004533 11615721634 0032176 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class CustomFieldsController < ApplicationController layout 'admin' before_filter :require_admin def index @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name } @tab = params[:tab] || 'IssueCustomField' end def new @custom_field = begin if params[:type].to_s.match(/.+CustomField$/) params[:type].to_s.constantize.new(params[:custom_field]) end rescue end (redirect_to(:action => 'index'); return) unless @custom_field.is_a?(CustomField) if request.post? and @custom_field.save flash[:notice] = l(:notice_successful_create) call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) redirect_to :action => 'index', :tab => @custom_field.class.name else @trackers = Tracker.find(:all, :order => 'position') end end def edit @custom_field = CustomField.find(params[:id]) if request.post? and @custom_field.update_attributes(params[:custom_field]) flash[:notice] = l(:notice_successful_update) call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field) redirect_to :action => 'index', :tab => @custom_field.class.name else @trackers = Tracker.find(:all, :order => 'position') end end def destroy @custom_field = CustomField.find(params[:id]).destroy redirect_to :action => 'index', :tab => @custom_field.class.name rescue flash[:error] = l(:error_can_not_delete_custom_field) redirect_to :action => 'index' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/documents_controller.rb 0000664 0000000 0000000 00000006145 11615721634 0031340 0 ustar 00root root 0000000 0000000 # 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 DocumentsController < ApplicationController default_search_scope :documents model_object Document before_filter :find_project, :only => [:index, :new] before_filter :find_model_object, :except => [:index, :new] before_filter :find_project_from_association, :except => [:index, :new] before_filter :authorize helper :attachments def index @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' documents = @project.documents.find :all, :include => [:attachments, :category] case @sort_by when 'date' @grouped = documents.group_by {|d| d.updated_on.to_date } when 'title' @grouped = documents.group_by {|d| d.title.first.upcase} when 'author' @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} else @grouped = documents.group_by(&:category) end @document = @project.documents.build render :layout => false if request.xhr? end def show @attachments = @document.attachments.find(:all, :order => "created_on DESC") end def new @document = @project.documents.build(params[:document]) if request.post? and @document.save attachments = Attachment.attach_files(@document, params[:attachments]) render_attachment_warning_if_needed(@document) flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index', :project_id => @project end end def edit @categories = DocumentCategory.all if request.post? and @document.update_attributes(params[:document]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :id => @document end end def destroy @document.destroy redirect_to :controller => 'documents', :action => 'index', :project_id => @project end def add_attachment attachments = Attachment.attach_files(@document, params[:attachments]) render_attachment_warning_if_needed(@document) Mailer.deliver_attachments_added(attachments[:files]) if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added') redirect_to :action => 'show', :id => @document end private def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/enumerations_controller.rb 0000664 0000000 0000000 00000005256 11615721634 0032052 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class EnumerationsController < ApplicationController layout 'admin' before_filter :require_admin helper :custom_fields include CustomFieldsHelper def index list render :action => 'list' end # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html) verify :method => :post, :only => [ :destroy, :create, :update ], :redirect_to => { :action => :list } def list end def new begin @enumeration = params[:type].constantize.new rescue NameError @enumeration = Enumeration.new end end def create @enumeration = Enumeration.new(params[:enumeration]) @enumeration.type = params[:enumeration][:type] if @enumeration.save flash[:notice] = l(:notice_successful_create) redirect_to :action => 'list', :type => @enumeration.type else render :action => 'new' end end def edit @enumeration = Enumeration.find(params[:id]) end def update @enumeration = Enumeration.find(params[:id]) @enumeration.type = params[:enumeration][:type] if params[:enumeration][:type] if @enumeration.update_attributes(params[:enumeration]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'list', :type => @enumeration.type else render :action => 'edit' end end def destroy @enumeration = Enumeration.find(params[:id]) if !@enumeration.in_use? # No associated objects @enumeration.destroy redirect_to :action => 'index' return elsif params[:reassign_to_id] if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) @enumeration.destroy(reassign_to) redirect_to :action => 'index' return end end @enumerations = @enumeration.class.find(:all) - [@enumeration] #rescue # flash[:error] = 'Unable to delete enumeration' # redirect_to :action => 'index' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/files_controller.rb 0000664 0000000 0000000 00000002411 11615721634 0030431 0 ustar 00root root 0000000 0000000 class FilesController < ApplicationController menu_item :files before_filter :find_project_by_project_id before_filter :authorize helper :sort include SortHelper def index sort_init 'filename', 'asc' sort_update 'filename' => "#{Attachment.table_name}.filename", 'created_on' => "#{Attachment.table_name}.created_on", 'size' => "#{Attachment.table_name}.filesize", 'downloads' => "#{Attachment.table_name}.downloads" @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)] @containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse render :layout => !request.xhr? end def new @versions = @project.versions.sort end def create container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id])) attachments = Attachment.attach_files(container, params[:attachments]) render_attachment_warning_if_needed(container) if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') Mailer.deliver_attachments_added(attachments[:files]) end redirect_to project_files_path(@project) end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/gantts_controller.rb 0000664 0000000 0000000 00000001773 11615721634 0030641 0 ustar 00root root 0000000 0000000 class GanttsController < ApplicationController menu_item :gantt before_filter :find_optional_project rescue_from Query::StatementInvalid, :with => :query_statement_invalid helper :gantt helper :issues helper :projects helper :queries include QueriesHelper helper :sort include SortHelper include Redmine::Export::PDF def show @gantt = Redmine::Helpers::Gantt.new(params) @gantt.project = @project retrieve_query @query.group_by = nil @gantt.query = @query if @query.valid? basename = (@project ? "#{@project.identifier}-" : '') + 'gantt' respond_to do |format| format.html { render :action => "show", :layout => !request.xhr? } format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") } end end def update show end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/groups_controller.rb 0000664 0000000 0000000 00000012136 11615721634 0030653 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class GroupsController < ApplicationController layout 'admin' before_filter :require_admin helper :custom_fields # GET /groups # GET /groups.xml def index @groups = Group.find(:all, :order => 'lastname') respond_to do |format| format.html # index.html.erb format.xml { render :xml => @groups } end end # GET /groups/1 # GET /groups/1.xml def show @group = Group.find(params[:id]) respond_to do |format| format.html # show.html.erb format.xml { render :xml => @group } end end # GET /groups/new # GET /groups/new.xml def new @group = Group.new respond_to do |format| format.html # new.html.erb format.xml { render :xml => @group } end end # GET /groups/1/edit def edit @group = Group.find(params[:id], :include => :projects) end # POST /groups # POST /groups.xml def create @group = Group.new(params[:group]) respond_to do |format| if @group.save flash[:notice] = l(:notice_successful_create) format.html { redirect_to(groups_path) } format.xml { render :xml => @group, :status => :created, :location => @group } else format.html { render :action => "new" } format.xml { render :xml => @group.errors, :status => :unprocessable_entity } end end end # PUT /groups/1 # PUT /groups/1.xml def update @group = Group.find(params[:id]) respond_to do |format| if @group.update_attributes(params[:group]) flash[:notice] = l(:notice_successful_update) format.html { redirect_to(groups_path) } format.xml { head :ok } else format.html { render :action => "edit" } format.xml { render :xml => @group.errors, :status => :unprocessable_entity } end end end # DELETE /groups/1 # DELETE /groups/1.xml def destroy @group = Group.find(params[:id]) @group.destroy respond_to do |format| format.html { redirect_to(groups_url) } format.xml { head :ok } end end def add_users @group = Group.find(params[:id]) users = User.find_all_by_id(params[:user_ids]) @group.users << users if request.post? respond_to do |format| format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users' users.each {|user| page.visual_effect(:highlight, "user-#{user.id}") } } } end end def remove_user @group = Group.find(params[:id]) @group.users.delete(User.find(params[:user_id])) if request.post? respond_to do |format| format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'users' } format.js { render(:update) {|page| page.replace_html "tab-content-users", :partial => 'groups/users'} } end end def autocomplete_for_user @group = Group.find(params[:id]) @users = User.active.like(params[:q]).find(:all, :limit => 100) - @group.users render :layout => false end def edit_membership @group = Group.find(params[:id]) @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) @membership.save if request.post? respond_to do |format| if @membership.valid? format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'groups/memberships' page.visual_effect(:highlight, "member-#{@membership.id}") } } else format.js { render(:update) {|page| page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) } } end end end def destroy_membership @group = Group.find(params[:id]) Member.find(params[:membership_id]).destroy if request.post? respond_to do |format| format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'groups/memberships'} } end end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/help_controller.rb 0000664 0000000 0000000 00000000153 11615721634 0030260 0 ustar 00root root 0000000 0000000 class HelpController < ApplicationController def wiki_syntax end def wiki_syntax_detailed end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/issue_categories_controller.rb 0000664 0000000 0000000 00000006444 11615721634 0032676 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class IssueCategoriesController < ApplicationController menu_item :settings model_object IssueCategory before_filter :find_model_object, :except => :new before_filter :find_project_from_association, :except => :new before_filter :find_project, :only => :new before_filter :authorize verify :method => :post, :only => :destroy def new @category = @project.issue_categories.build(params[:category]) if request.post? if @category.save respond_to do |format| format.html do flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project end format.js do # IE doesn't support the replace_html rjs method for select box options render(:update) {|page| page.replace "issue_category_id", content_tag('select', '' + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') } end end else respond_to do |format| format.html format.js do render(:update) {|page| page.alert(@category.errors.full_messages.join('\n')) } end end end end end def edit if request.post? and @category.update_attributes(params[:category]) flash[:notice] = l(:notice_successful_update) redirect_to :controller => 'projects', :action => 'settings', :tab => 'categories', :id => @project end end def destroy @issue_count = @category.issues.size if @issue_count == 0 # No issue assigned to this category @category.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' return elsif params[:todo] reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) if params[:todo] == 'reassign' @category.destroy(reassign_to) redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' return end @categories = @project.issue_categories - [@category] end private # Wrap ApplicationController's find_model_object method to set # @category instead of just @issue_category def find_model_object super @category = @object end def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/issue_moves_controller.rb 0000664 0000000 0000000 00000004611 11615721634 0031674 0 ustar 00root root 0000000 0000000 class IssueMovesController < ApplicationController default_search_scope :issues before_filter :find_issues, :check_project_uniqueness before_filter :authorize def new prepare_for_issue_move render :layout => false if request.xhr? end def create prepare_for_issue_move if request.post? new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) unsaved_issue_ids = [] moved_issues = [] @issues.each do |issue| issue.reload issue.init_journal(User.current) issue.current_journal.notes = @notes if @notes.present? call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params)}) moved_issues << r else unsaved_issue_ids << issue.id end end set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) if params[:follow] if @issues.size == 1 && moved_issues.size == 1 redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first else redirect_to :controller => 'issues', :action => 'index', :project_id => (@target_project || @project) end else redirect_to :controller => 'issues', :action => 'index', :project_id => @project end return end end private def prepare_for_issue_move @issues.sort! @copy = params[:copy_options] && params[:copy_options][:copy] @allowed_projects = Issue.allowed_target_projects_on_move @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] @target_project ||= @project @trackers = @target_project.trackers @available_statuses = Workflow.available_statuses(@project) @notes = params[:notes] @notes ||= '' end def extract_changed_attributes_for_move(params) changed_attributes = {} [:assigned_to_id, :status_id, :start_date, :due_date, :priority_id].each do |valid_attribute| unless params[valid_attribute].blank? changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) end end changed_attributes end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/issue_relations_controller.rb 0000664 0000000 0000000 00000004622 11615721634 0032545 0 ustar 00root root 0000000 0000000 # 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 IssueRelationsController < ApplicationController before_filter :find_issue, :find_project_from_association, :authorize def new @relation = IssueRelation.new(params[:relation]) @relation.issue_from = @issue if params[:relation] && m = params[:relation][:issue_to_id].to_s.match(/^#?(\d+)$/) @relation.issue_to = Issue.visible.find_by_id(m[1].to_i) end @relation.save if request.post? respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } format.js do @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } render :update do |page| page.replace_html "relations", :partial => 'issues/relations' if @relation.errors.empty? page << "$('relation_delay').value = ''" page << "$('relation_issue_to_id').value = ''" end end end end end def destroy relation = IssueRelation.find(params[:id]) if request.post? && @issue.relations.include?(relation) relation.destroy @issue.reload end respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } format.js { @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } render(:update) {|page| page.replace_html "relations", :partial => 'issues/relations'} } end end private def find_issue @issue = @object = Issue.find(params[:issue_id]) rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/issue_statuses_controller.rb 0000664 0000000 0000000 00000004444 11615721634 0032422 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class IssueStatusesController < ApplicationController layout 'admin' before_filter :require_admin verify :method => :post, :only => [ :destroy, :create, :update, :move, :update_issue_done_ratio ], :redirect_to => { :action => :index } def index @issue_status_pages, @issue_statuses = paginate :issue_statuses, :per_page => 25, :order => "position" render :action => "index", :layout => false if request.xhr? end def new @issue_status = IssueStatus.new end def create @issue_status = IssueStatus.new(params[:issue_status]) if @issue_status.save flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index' else render :action => 'new' end end def edit @issue_status = IssueStatus.find(params[:id]) end def update @issue_status = IssueStatus.find(params[:id]) if @issue_status.update_attributes(params[:issue_status]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' else render :action => 'edit' end end def destroy IssueStatus.find(params[:id]).destroy redirect_to :action => 'index' rescue flash[:error] = l(:error_unable_delete_issue_status) redirect_to :action => 'index' end def update_issue_done_ratio if IssueStatus.update_issue_done_ratios flash[:notice] = l(:notice_issue_done_ratios_updated) else flash[:error] = l(:error_issue_done_ratios_not_updated) end redirect_to :action => 'index' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/issues_controller.rb 0000664 0000000 0000000 00000027735 11615721634 0030662 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2008 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 IssuesController < ApplicationController menu_item :new_issue, :only => [:new, :create] default_search_scope :issues before_filter :find_issue, :only => [:show, :edit, :update] before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :move, :perform_move, :destroy] before_filter :check_project_uniqueness, :only => [:move, :perform_move] before_filter :find_project, :only => [:new, :create] before_filter :authorize, :except => [:index] before_filter :find_optional_project, :only => [:index] before_filter :check_for_default_issue_status, :only => [:new, :create] before_filter :build_new_issue_from_params, :only => [:new, :create] accept_key_auth :index, :show, :create, :update, :destroy rescue_from Query::StatementInvalid, :with => :query_statement_invalid helper :journals helper :projects include ProjectsHelper helper :custom_fields include CustomFieldsHelper helper :issue_relations include IssueRelationsHelper helper :watchers include WatchersHelper helper :attachments include AttachmentsHelper helper :queries include QueriesHelper helper :repositories include RepositoriesHelper helper :sort include SortHelper include IssuesHelper helper :timelog helper :gantt include Redmine::Export::PDF verify :method => [:post, :delete], :only => :destroy, :render => { :nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :post, :only => :bulk_update, :render => {:nothing => true, :status => :method_not_allowed } verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def index retrieve_query sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) sort_update(@query.sortable_columns) if @query.valid? case params[:format] when 'csv', 'pdf' @limit = Setting.issues_export_limit.to_i when 'atom' @limit = Setting.feeds_limit.to_i when 'xml', 'json' @offset, @limit = api_offset_and_limit else @limit = per_page_option end @issue_count = @query.issue_count @issue_pages = Paginator.new self, @issue_count, @limit, params['page'] @offset ||= @issue_pages.current.offset @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], :order => sort_clause, :offset => @offset, :limit => @limit) @issue_count_by_group = @query.issue_count_by_group respond_to do |format| format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? } format.api format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } format.csv { send_data(issues_to_csv(@issues, @project), :type => 'text/csv; header=present', :filename => 'export.csv') } format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'export.pdf') } end else # Send html if the query is not valid render(:template => 'issues/index.rhtml', :layout => !request.xhr?) end rescue ActiveRecord::RecordNotFound render_404 end def show @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") @journals.each_with_index {|j,i| j.indice = i+1} @journals.reverse! if User.current.wants_comments_in_reverse_order? @changesets = @issue.changesets.visible.all @changesets.reverse! if User.current.wants_comments_in_reverse_order? @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @priorities = IssuePriority.all @time_entry = TimeEntry.new respond_to do |format| format.html { render :template => 'issues/show.rhtml' } format.api format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' } format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } end end # Add a new issue # The new issue will be created from an existing one if copy_from parameter is given def new respond_to do |format| format.html { render :action => 'new', :layout => !request.xhr? } format.js { render :partial => 'attributes' } end end def create call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) if @issue.save attachments = Attachment.attach_files(@issue, params[:attachments]) render_attachment_warning_if_needed(@issue) flash[:notice] = l(:notice_successful_create) call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| format.html { redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : { :action => 'show', :id => @issue }) } format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) } end return else respond_to do |format| format.html { render :action => 'new' } format.api { render_validation_errors(@issue) } end end end def edit update_issue_from_params @journal = @issue.current_journal respond_to do |format| format.html { } format.xml { } end end def update update_issue_from_params if @issue.save_issue_with_child_records(params, @time_entry) render_attachment_warning_if_needed(@issue) flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? respond_to do |format| format.html { redirect_back_or_default({:action => 'show', :id => @issue}) } format.api { head :ok } end else render_attachment_warning_if_needed(@issue) flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? @journal = @issue.current_journal respond_to do |format| format.html { render :action => 'edit' } format.api { render_validation_errors(@issue) } end end end # Bulk edit a set of issues def bulk_edit @issues.sort! @available_statuses = @projects.map{|p|Workflow.available_statuses(p)}.inject{|memo,w|memo & w} @custom_fields = @projects.map{|p|p.all_issue_custom_fields}.inject{|memo,c|memo & c} @assignables = @projects.map(&:assignable_users).inject{|memo,a| memo & a} @trackers = @projects.map(&:trackers).inject{|memo,t| memo & t} end def bulk_update @issues.sort! attributes = parse_params_for_bulk_issue_attributes(params) unsaved_issue_ids = [] @issues.each do |issue| issue.reload journal = issue.init_journal(User.current, params[:notes]) issue.safe_attributes = attributes call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) unless issue.save # Keep unsaved issue ids to display them in flash error unsaved_issue_ids << issue.id end end set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) redirect_back_or_default({:controller => 'issues', :action => 'index', :project_id => @project}) end def destroy @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f if @hours > 0 case params[:todo] when 'destroy' # nothing to do when 'nullify' TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues]) when 'reassign' reassign_to = @project.issues.find_by_id(params[:reassign_to_id]) if reassign_to.nil? flash.now[:error] = l(:error_issue_not_found_in_project) return else TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues]) end else # display the destroy form if it's a user request return unless api_request? end end @issues.each(&:destroy) respond_to do |format| format.html { redirect_back_or_default(:action => 'index', :project_id => @project) } format.api { head :ok } end end private def find_issue @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) @project = @issue.project rescue ActiveRecord::RecordNotFound render_404 end def find_project project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] @project = Project.find(project_id) rescue ActiveRecord::RecordNotFound render_404 end # Used by #edit and #update to set some common instance variables # from the params # TODO: Refactor, not everything in here is needed by #edit def update_issue_from_params @allowed_statuses = @issue.new_statuses_allowed_to(User.current) @priorities = IssuePriority.all @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @time_entry = TimeEntry.new @time_entry.attributes = params[:time_entry] @notes = params[:notes] || (params[:issue].present? ? params[:issue][:notes] : nil) @issue.init_journal(User.current, @notes) @issue.safe_attributes = params[:issue] end # TODO: Refactor, lots of extra code in here # TODO: Changing tracker on an existing issue should not trigger this def build_new_issue_from_params if params[:id].blank? @issue = Issue.new @issue.copy_from(params[:copy_from]) if params[:copy_from] @issue.project = @project else @issue = @project.issues.visible.find(params[:id]) end @issue.project = @project # Tracker must be set before custom field values @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) if @issue.tracker.nil? render_error l(:error_no_tracker_in_project) return false end @issue.start_date ||= Date.today if params[:issue].is_a?(Hash) @issue.safe_attributes = params[:issue] if User.current.allowed_to?(:add_issue_watchers, @project) && @issue.new_record? @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] end end @issue.author = User.current @priorities = IssuePriority.all @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end def check_for_default_issue_status if IssueStatus.default.nil? render_error l(:error_no_default_issue_status) return false end end def parse_params_for_bulk_issue_attributes(params) attributes = (params[:issue] || {}).reject {|k,v| v.blank?} attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] attributes end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/journals_controller.rb 0000664 0000000 0000000 00000006672 11615721634 0031201 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006-2008 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 JournalsController < ApplicationController before_filter :find_journal, :only => [:edit] before_filter :find_issue, :only => [:new] before_filter :find_optional_project, :only => [:index] before_filter :authorize, :only => [:new, :edit] accept_key_auth :index helper :issues helper :queries include QueriesHelper helper :sort include SortHelper helper :custom_fields def index retrieve_query sort_init 'id', 'desc' sort_update(@query.sortable_columns) if @query.valid? @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", :limit => 25) end @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) render :layout => false, :content_type => 'application/atom+xml' rescue ActiveRecord::RecordNotFound render_404 end def new journal = Journal.find(params[:journal_id]) if params[:journal_id] if journal user = journal.user text = journal.notes else user = @issue.author text = @issue.description end # Replaces pre blocks with [...] text = text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]') content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" render(:update) { |page| page.<< "$('notes').value = \"#{escape_javascript content}\";" page.show 'update' page << "Form.Element.focus('notes');" page << "Element.scrollTo('update');" page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" } end def edit if request.post? @journal.update_attributes(:notes => params[:notes]) if params[:notes] @journal.destroy if @journal.details.empty? && @journal.notes.blank? call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id } format.js { render :action => 'update' } end end end private def find_journal @journal = Journal.find(params[:id]) (render_403; return false) unless @journal.editable_by?(User.current) @project = @journal.journalized.project rescue ActiveRecord::RecordNotFound render_404 end # TODO: duplicated in IssuesController def find_issue @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) @project = @issue.project rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/ldap_auth_sources_controller.rb0000664 0000000 0000000 00000001625 11615721634 0033041 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class LdapAuthSourcesController < AuthSourcesController protected def auth_source_class AuthSourceLdap end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/mail_handler_controller.rb 0000664 0000000 0000000 00000003064 11615721634 0031753 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006-2008 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 MailHandlerController < ActionController::Base before_filter :check_credential verify :method => :post, :only => :index, :render => { :nothing => true, :status => 405 } # Submits an incoming email to MailHandler def index options = params.dup email = options.delete(:email) if MailHandler.receive(email, options) render :nothing => true, :status => :created else render :nothing => true, :status => :unprocessable_entity end end private def check_credential User.current = nil unless Setting.mail_handler_api_enabled? && params[:key].to_s == Setting.mail_handler_api_key render :text => 'Access denied. Incoming emails WS is disabled or key is invalid.', :status => 403 end end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/members_controller.rb 0000664 0000000 0000000 00000006567 11615721634 0031001 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class MembersController < ApplicationController model_object Member before_filter :find_model_object, :except => [:new, :autocomplete_for_member] before_filter :find_project_from_association, :except => [:new, :autocomplete_for_member] before_filter :find_project, :only => [:new, :autocomplete_for_member] before_filter :authorize def new members = [] if params[:member] && request.post? attrs = params[:member].dup if (user_ids = attrs.delete(:user_ids)) user_ids.each do |user_id| members << Member.new(attrs.merge(:user_id => user_id)) end else members << Member.new(attrs) end @project.members << members end respond_to do |format| if members.present? && members.all? {|m| m.valid? } format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members' page << 'hideOnLoad()' members.each {|member| page.visual_effect(:highlight, "member-#{member.id}") } } } else format.js { render(:update) {|page| errors = members.collect {|m| m.errors.full_messages }.flatten.uniq page.alert(l(:notice_failed_to_save_members, :errors => errors.join(', '))) } } end end end def edit if request.post? and @member.update_attributes(params[:member]) respond_to do |format| format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members' page << 'hideOnLoad()' page.visual_effect(:highlight, "member-#{@member.id}") } } end end end def destroy if request.post? && @member.deletable? @member.destroy end respond_to do |format| format.html { redirect_to :controller => 'projects', :action => 'settings', :tab => 'members', :id => @project } format.js { render(:update) {|page| page.replace_html "tab-content-members", :partial => 'projects/settings/members' page << 'hideOnLoad()' } } end end def autocomplete_for_member @principals = Principal.active.like(params[:q]).find(:all, :limit => 100) - @project.principals render :layout => false end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/messages_controller.rb 0000664 0000000 0000000 00000013300 11615721634 0031135 0 ustar 00root root 0000000 0000000 # 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 MessagesController < ApplicationController menu_item :boards default_search_scope :messages before_filter :find_board, :only => [:new, :preview] before_filter :find_message, :except => [:new, :preview] before_filter :authorize, :except => [:preview, :edit, :destroy] verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } verify :xhr => true, :only => :quote helper :watchers helper :attachments include AttachmentsHelper REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) # Show a topic and its replies def show page = params[:page] # Find the page of the requested reply if params[:r] && page.nil? offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) page = 1 + offset / REPLIES_PER_PAGE end @reply_count = @topic.children.count @reply_pages = Paginator.new self, @reply_count, REPLIES_PER_PAGE, page @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}], :order => "#{Message.table_name}.created_on ASC", :limit => @reply_pages.items_per_page, :offset => @reply_pages.current.offset) @reply = Message.new(:subject => "RE: #{@message.subject}") render :action => "show", :layout => false if request.xhr? end # Create a new topic def new @message = Message.new(params[:message]) @message.author = User.current @message.board = @board if params[:message] && User.current.allowed_to?(:edit_messages, @project) @message.locked = params[:message]['locked'] @message.sticky = params[:message]['sticky'] end if request.post? && @message.save call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) attachments = Attachment.attach_files(@message, params[:attachments]) render_attachment_warning_if_needed(@message) redirect_to :action => 'show', :id => @message end end # Reply to a topic def reply @reply = Message.new(params[:reply]) @reply.author = User.current @reply.board = @board @topic.children << @reply if !@reply.new_record? call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) attachments = Attachment.attach_files(@reply, params[:attachments]) render_attachment_warning_if_needed(@reply) end redirect_to :action => 'show', :id => @topic, :r => @reply end # Edit a message def edit (render_403; return false) unless @message.editable_by?(User.current) if params[:message] @message.locked = params[:message]['locked'] @message.sticky = params[:message]['sticky'] end if request.post? && @message.update_attributes(params[:message]) attachments = Attachment.attach_files(@message, params[:attachments]) render_attachment_warning_if_needed(@message) flash[:notice] = l(:notice_successful_update) @message.reload redirect_to :action => 'show', :board_id => @message.board, :id => @message.root, :r => (@message.parent_id && @message.id) end end # Delete a messages def destroy (render_403; return false) unless @message.destroyable_by?(User.current) @message.destroy redirect_to @message.parent.nil? ? { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } : { :action => 'show', :id => @message.parent, :r => @message } end def quote user = @message.author text = @message.content subject = @message.subject.gsub('"', '\"') subject = "RE: #{subject}" unless subject.starts_with?('RE:') content = "#{ll(Setting.default_language, :text_user_wrote, user)}\\n> " content << text.to_s.strip.gsub(%r{
((.|\s)*?)}m, '[...]').gsub('"', '\"').gsub(/(\r?\n|\r\n?)/, "\\n> ") + "\\n\\n" render(:update) { |page| page << "$('reply_subject').value = \"#{subject}\";" page.<< "$('message_content').value = \"#{content}\";" page.show 'reply' page << "Form.Element.focus('message_content');" page << "Element.scrollTo('reply');" page << "$('message_content').scrollTop = $('message_content').scrollHeight - $('message_content').clientHeight;" } end def preview message = @board.messages.find_by_id(params[:id]) @attachements = message.attachments if message @text = (params[:message] || params[:reply])[:content] render :partial => 'common/preview' end private def find_message find_board @message = @board.messages.find(params[:id], :include => :parent) @topic = @message.root rescue ActiveRecord::RecordNotFound render_404 end def find_board @board = Board.find(params[:board_id], :include => :project) @project = @board.project rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/my_controller.rb 0000664 0000000 0000000 00000013210 11615721634 0027753 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class MyController < ApplicationController before_filter :require_login helper :issues helper :users helper :custom_fields BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, 'issuesreportedbyme' => :label_reported_issues, 'issueswatched' => :label_watched_issues, 'news' => :label_news_latest, 'calendar' => :label_calendar, 'documents' => :label_document_plural, 'timelog' => :label_spent_time }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], 'right' => ['issuesreportedbyme'] }.freeze verify :xhr => true, :only => [:add_block, :remove_block, :order_blocks] def index page render :action => 'page' end # Show user's page def page @user = User.current @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT end # Edit user's account def account @user = User.current @pref = @user.pref if request.post? @user.safe_attributes = params[:user] @user.pref.attributes = params[:pref] @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') if @user.save @user.pref.save @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) set_language_if_valid @user.language flash[:notice] = l(:notice_account_updated) redirect_to :action => 'account' return end end end # Manage user's password def password @user = User.current unless @user.change_password_allowed? flash[:error] = l(:notice_can_t_change_password) redirect_to :action => 'account' return end if request.post? if @user.check_password?(params[:password]) @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] if @user.save flash[:notice] = l(:notice_account_password_updated) redirect_to :action => 'account' end else flash[:error] = l(:notice_account_wrong_password) end end end # Create a new feeds key def reset_rss_key if request.post? if User.current.rss_token User.current.rss_token.destroy User.current.reload end User.current.rss_key flash[:notice] = l(:notice_feeds_access_key_reseted) end redirect_to :action => 'account' end # Create a new API key def reset_api_key if request.post? if User.current.api_token User.current.api_token.destroy User.current.reload end User.current.api_key flash[:notice] = l(:notice_api_access_key_reseted) end redirect_to :action => 'account' end # User's page layout configuration def page_layout @user = User.current @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup @block_options = [] BLOCKS.each {|k, v| @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize]} end # Add a block to user's page # The block is added on top of the page # params[:block] : id of the block to add def add_block block = params[:block].to_s.underscore (render :nothing => true; return) unless block && (BLOCKS.keys.include? block) @user = User.current layout = @user.pref[:my_page_layout] || {} # remove if already present in a group %w(top left right).each {|f| (layout[f] ||= []).delete block } # add it on top layout['top'].unshift block @user.pref[:my_page_layout] = layout @user.pref.save render :partial => "block", :locals => {:user => @user, :block_name => block} end # Remove a block to user's page # params[:block] : id of the block to remove def remove_block block = params[:block].to_s.underscore @user = User.current # remove block in all groups layout = @user.pref[:my_page_layout] || {} %w(top left right).each {|f| (layout[f] ||= []).delete block } @user.pref[:my_page_layout] = layout @user.pref.save render :nothing => true end # Change blocks order on user's page # params[:group] : group to order (top, left or right) # params[:list-(top|left|right)] : array of block ids of the group def order_blocks group = params[:group] @user = User.current if group.is_a?(String) group_items = (params["list-#{group}"] || []).collect(&:underscore) if group_items and group_items.is_a? Array layout = @user.pref[:my_page_layout] || {} # remove group blocks if they are presents in other groups %w(top left right).each {|f| layout[f] = (layout[f] || []) - group_items } layout[group] = group_items @user.pref[:my_page_layout] = layout @user.pref.save end end render :nothing => true end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/news_controller.rb 0000664 0000000 0000000 00000006451 11615721634 0030313 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class NewsController < ApplicationController default_search_scope :news model_object News before_filter :find_model_object, :except => [:new, :create, :index] before_filter :find_project_from_association, :except => [:new, :create, :index] before_filter :find_project, :only => [:new, :create] before_filter :authorize, :except => [:index] before_filter :find_optional_project, :only => :index accept_key_auth :index def index case params[:format] when 'xml', 'json' @offset, @limit = api_offset_and_limit else @limit = 10 end scope = @project ? @project.news.visible : News.visible @news_count = scope.count @news_pages = Paginator.new self, @news_count, @limit, params['page'] @offset ||= @news_pages.current.offset @newss = scope.all(:include => [:author, :project], :order => "#{News.table_name}.created_on DESC", :offset => @offset, :limit => @limit) respond_to do |format| format.html { render :layout => false if request.xhr? } format.api format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } end end def show @comments = @news.comments @comments.reverse! if User.current.wants_comments_in_reverse_order? end def new @news = News.new(:project => @project, :author => User.current) end def create @news = News.new(:project => @project, :author => User.current) if request.post? @news.attributes = params[:news] if @news.save flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'news', :action => 'index', :project_id => @project else render :action => 'new' end end end def edit end def update if request.put? and @news.update_attributes(params[:news]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :id => @news else render :action => 'edit' end end def destroy @news.destroy redirect_to :action => 'index', :project_id => @project end private def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end def find_optional_project return true unless params[:project_id] @project = Project.find(params[:project_id]) authorize rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/previews_controller.rb 0000664 0000000 0000000 00000001675 11615721634 0031206 0 ustar 00root root 0000000 0000000 class PreviewsController < ApplicationController before_filter :find_project def issue @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? if @issue @attachements = @issue.attachments @description = params[:issue] && params[:issue][:description] if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") @description = nil end @notes = params[:notes] else @description = (params[:issue] ? params[:issue][:description] : nil) end render :layout => false end def news @text = (params[:news] ? params[:news][:description] : nil) render :partial => 'common/preview' end private def find_project project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] @project = Project.find(project_id) rescue ActiveRecord::RecordNotFound render_404 end end project_enumerations_controller.rb 0000664 0000000 0000000 00000001530 11615721634 0033510 0 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers class ProjectEnumerationsController < ApplicationController before_filter :find_project_by_project_id before_filter :authorize def update if request.put? && params[:enumerations] Project.transaction do params[:enumerations].each do |id, activity| @project.update_or_create_time_entry_activity(id, activity) end end flash[:notice] = l(:notice_successful_update) end redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project end def destroy @project.time_entry_activities.each do |time_entry_activity| time_entry_activity.destroy(time_entry_activity.parent) end flash[:notice] = l(:notice_successful_update) redirect_to :controller => 'projects', :action => 'settings', :tab => 'activities', :id => @project end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/projects_controller.rb 0000664 0000000 0000000 00000023567 11615721634 0031177 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class ProjectsController < ApplicationController menu_item :overview menu_item :roadmap, :only => :roadmap menu_item :settings, :only => :settings before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ] before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy] before_filter :authorize_global, :only => [:new, :create] before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] accept_key_auth :index, :show, :create, :update, :destroy after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| if controller.request.post? controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt' end end helper :sort include SortHelper helper :custom_fields include CustomFieldsHelper helper :issues helper :queries include QueriesHelper helper :repositories include RepositoriesHelper include ProjectsHelper # Lists visible projects def index respond_to do |format| format.html { @projects = Project.visible.find(:all, :order => 'lft') } format.api { @offset, @limit = api_offset_and_limit @project_count = Project.visible.count @projects = Project.visible.all(:offset => @offset, :limit => @limit, :order => 'lft') } format.atom { projects = Project.visible.find(:all, :order => 'created_on DESC', :limit => Setting.feeds_limit.to_i) render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") } end end def new @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all @project = Project.new(params[:project]) end verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all @project = Project.new @project.safe_attributes = params[:project] if validate_parent_id && @project.save @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') # Add current user as a project member if he is not admin unless User.current.admin? r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first m = Member.new(:user => User.current, :roles => [r]) @project.members << m end respond_to do |format| format.html { flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'projects', :action => 'settings', :id => @project } format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } end else respond_to do |format| format.html { render :action => 'new' } format.api { render_validation_errors(@project) } end end end def copy @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all @root_projects = Project.find(:all, :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}", :order => 'name') @source_project = Project.find(params[:id]) if request.get? @project = Project.copy_from(@source_project) if @project @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? else redirect_to :controller => 'admin', :action => 'projects' end else Mailer.with_deliveries(params[:notifications] == '1') do @project = Project.new @project.safe_attributes = params[:project] @project.enabled_module_names = params[:enabled_modules] if validate_parent_id && @project.copy(@source_project, :only => params[:only]) @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'projects', :action => 'settings', :id => @project elsif !@project.new_record? # Project was created # But some objects were not copied due to validation failures # (eg. issues from disabled trackers) # TODO: inform about that redirect_to :controller => 'projects', :action => 'settings', :id => @project end end end rescue ActiveRecord::RecordNotFound redirect_to :controller => 'admin', :action => 'projects' end # Show @project def show if params[:jump] # try to redirect to the requested menu item redirect_to_project_menu_item(@project, params[:jump]) && return end @users_by_role = @project.users_by_role @subprojects = @project.children.visible @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") @trackers = @project.rolled_up_trackers cond = @project.project_condition(Setting.display_subprojects_issues?) @open_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false]) @total_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => cond) TimeEntry.visible_by(User.current) do @total_hours = TimeEntry.sum(:hours, :include => :project, :conditions => cond).to_f end @key = User.current.rss_key respond_to do |format| format.html format.api end end def settings @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @issue_category ||= IssueCategory.new @member ||= @project.members.new @trackers = Tracker.all @repository ||= @project.repository @wiki ||= @project.wiki end def edit end # TODO: convert to PUT only verify :method => [:post, :put], :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def update @project.safe_attributes = params[:project] if validate_parent_id && @project.save @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) redirect_to :action => 'settings', :id => @project } format.api { head :ok } end else respond_to do |format| format.html { settings render :action => 'settings' } format.api { render_validation_errors(@project) } end end end verify :method => :post, :only => :modules, :render => {:nothing => true, :status => :method_not_allowed } def modules @project.enabled_module_names = params[:enabled_module_names] flash[:notice] = l(:notice_successful_update) redirect_to :action => 'settings', :id => @project, :tab => 'modules' end def archive if request.post? unless @project.archive flash[:error] = l(:error_can_not_archive_project) end end redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) end def unarchive @project.unarchive if request.post? && !@project.active? redirect_to(url_for(:controller => 'admin', :action => 'projects', :status => params[:status])) end # Delete @project def destroy @project_to_destroy = @project if request.get? # display confirmation view else if api_request? || params[:confirm] @project_to_destroy.destroy respond_to do |format| format.html { redirect_to :controller => 'admin', :action => 'projects' } format.api { head :ok } end end end # hide project in layout @project = nil end private def find_optional_project return true unless params[:id] @project = Project.find(params[:id]) authorize rescue ActiveRecord::RecordNotFound render_404 end # Validates parent_id param according to user's permissions # TODO: move it to Project model in a validation that depends on User.current def validate_parent_id return true if User.current.admin? parent_id = params[:project] && params[:project][:parent_id] if parent_id || @project.new_record? parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i) unless @project.allowed_parents.include?(parent) @project.errors.add :parent_id, :invalid return false end end true end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/queries_controller.rb 0000664 0000000 0000000 00000005667 11615721634 0031024 0 ustar 00root root 0000000 0000000 # 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 QueriesController < ApplicationController menu_item :issues before_filter :find_query, :except => :new before_filter :find_optional_project, :only => :new def new @query = Query.new(params[:query]) @query.project = params[:query_is_for_all] ? nil : @project @query.user = User.current @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? @query.column_names = nil if params[:default_columns] @query.add_filters(params[:fields], params[:operators], params[:values]) if params[:fields] @query.group_by ||= params[:group_by] if request.post? && params[:confirm] && @query.save flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query return end render :layout => false if request.xhr? end def edit if request.post? @query.filters = {} @query.add_filters(params[:fields], params[:operators], params[:values]) if params[:fields] @query.attributes = params[:query] @query.project = nil if params[:query_is_for_all] @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? @query.column_names = nil if params[:default_columns] if @query.save flash[:notice] = l(:notice_successful_update) redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :query_id => @query end end end def destroy @query.destroy if request.post? redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 end private def find_query @query = Query.find(params[:id]) @project = @query.project render_403 unless @query.editable_by?(User.current) rescue ActiveRecord::RecordNotFound render_404 end def find_optional_project @project = Project.find(params[:project_id]) if params[:project_id] render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/reports_controller.rb 0000664 0000000 0000000 00000006362 11615721634 0031036 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class ReportsController < ApplicationController menu_item :issues before_filter :find_project, :authorize, :find_issue_statuses def issue_report @trackers = @project.trackers @versions = @project.shared_versions.sort @priorities = IssuePriority.all @categories = @project.issue_categories @assignees = @project.members.collect { |m| m.user }.sort @authors = @project.members.collect { |m| m.user }.sort @subprojects = @project.descendants.visible @issues_by_tracker = Issue.by_tracker(@project) @issues_by_version = Issue.by_version(@project) @issues_by_priority = Issue.by_priority(@project) @issues_by_category = Issue.by_category(@project) @issues_by_assigned_to = Issue.by_assigned_to(@project) @issues_by_author = Issue.by_author(@project) @issues_by_subproject = Issue.by_subproject(@project) || [] render :template => "reports/issue_report" end def issue_report_details case params[:detail] when "tracker" @field = "tracker_id" @rows = @project.trackers @data = Issue.by_tracker(@project) @report_title = l(:field_tracker) when "version" @field = "fixed_version_id" @rows = @project.shared_versions.sort @data = Issue.by_version(@project) @report_title = l(:field_version) when "priority" @field = "priority_id" @rows = IssuePriority.all @data = Issue.by_priority(@project) @report_title = l(:field_priority) when "category" @field = "category_id" @rows = @project.issue_categories @data = Issue.by_category(@project) @report_title = l(:field_category) when "assigned_to" @field = "assigned_to_id" @rows = @project.members.collect { |m| m.user }.sort @data = Issue.by_assigned_to(@project) @report_title = l(:field_assigned_to) when "author" @field = "author_id" @rows = @project.members.collect { |m| m.user }.sort @data = Issue.by_author(@project) @report_title = l(:field_author) when "subproject" @field = "project_id" @rows = @project.descendants.visible @data = Issue.by_subproject(@project) || [] @report_title = l(:field_subproject) end respond_to do |format| if @field format.html {} else format.html { redirect_to :action => 'issue_report', :id => @project } end end end private def find_issue_statuses @statuses = IssueStatus.find(:all, :order => 'position') end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/repositories_controller.rb 0000664 0000000 0000000 00000026420 11615721634 0032064 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'SVG/Graph/Bar' require 'SVG/Graph/BarHorizontal' require 'digest/sha1' class ChangesetNotFound < Exception; end class InvalidRevisionParam < Exception; end class RepositoriesController < ApplicationController menu_item :repository menu_item :settings, :only => :edit default_search_scope :changesets before_filter :find_repository, :except => :edit before_filter :find_project, :only => :edit before_filter :authorize accept_key_auth :revisions rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed def edit @repository = @project.repository if !@repository @repository = Repository.factory(params[:repository_scm]) @repository.project = @project if @repository end if request.post? && @repository @repository.attributes = params[:repository] @repository.save end render(:update) do |page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository' if @repository && !@project.repository @project.reload #needed to reload association page.replace_html "main-menu", render_main_menu(@project) end end end def committers @committers = @repository.committers @users = @project.users additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? @users.compact! @users.sort! if request.post? && params[:committers].is_a?(Hash) # Build a hash with repository usernames as keys and corresponding user ids as values @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h} flash[:notice] = l(:notice_successful_update) redirect_to :action => 'committers', :id => @project end end def destroy @repository.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository' end def show @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? @entries = @repository.entries(@path, @rev) if request.xhr? @entries ? render(:partial => 'dir_list_content') : render(:nothing => true) else (show_error_not_found; return) unless @entries @changesets = @repository.latest_changesets(@path, @rev) @properties = @repository.properties(@path, @rev) render :action => 'show' end end alias_method :browse, :show def changes @entry = @repository.entry(@path, @rev) (show_error_not_found; return) unless @entry @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i) @properties = @repository.properties(@path, @rev) @changeset = @repository.find_changeset_by_name(@rev) end def revisions @changeset_count = @repository.changesets.count @changeset_pages = Paginator.new self, @changeset_count, per_page_option, params['page'] @changesets = @repository.changesets.find(:all, :limit => @changeset_pages.items_per_page, :offset => @changeset_pages.current.offset, :include => [:user, :repository]) respond_to do |format| format.html { render :layout => false if request.xhr? } format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") } end end def entry @entry = @repository.entry(@path, @rev) (show_error_not_found; return) unless @entry # If the entry is a dir, show the browser (show; return) if @entry.is_dir? @content = @repository.cat(@path, @rev) (show_error_not_found; return) unless @content if 'raw' == params[:format] || @content.is_binary_data? || (@entry.size && @entry.size > Setting.file_max_size_displayed.to_i.kilobyte) # Force the download send_data @content, :filename => filename_for_content_disposition(@path.split('/').last) else # Prevent empty lines when displaying a file with Windows style eol @content.gsub!("\r\n", "\n") @changeset = @repository.find_changeset_by_name(@rev) end end def annotate @entry = @repository.entry(@path, @rev) (show_error_not_found; return) unless @entry @annotate = @repository.scm.annotate(@path, @rev) (render_error l(:error_scm_annotate); return) if @annotate.nil? || @annotate.empty? @changeset = @repository.find_changeset_by_name(@rev) end def revision raise ChangesetNotFound if @rev.blank? @changeset = @repository.find_changeset_by_name(@rev) raise ChangesetNotFound unless @changeset respond_to do |format| format.html format.js {render :layout => false} end rescue ChangesetNotFound show_error_not_found end def diff if params[:format] == 'diff' @diff = @repository.diff(@path, @rev, @rev_to) (show_error_not_found; return) unless @diff filename = "changeset_r#{@rev}" filename << "_r#{@rev_to}" if @rev_to send_data @diff.join, :filename => "#{filename}.diff", :type => 'text/x-patch', :disposition => 'attachment' else @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) # Save diff type as user preference if User.current.logged? && @diff_type != User.current.pref[:diff_type] User.current.pref[:diff_type] = @diff_type User.current.preference.save end @cache_key = "repositories/diff/#{@repository.id}/" + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}") unless read_fragment(@cache_key) @diff = @repository.diff(@path, @rev, @rev_to) show_error_not_found unless @diff end @changeset = @repository.find_changeset_by_name(@rev) @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to) 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 REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i def find_repository @project = Project.find(params[:id]) @repository = @project.repository (render_404; return false) unless @repository @path = params[:path].join('/') unless params[:path].nil? @path ||= '' @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].strip @rev_to = params[:rev_to] unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE) if @repository.branches.blank? raise InvalidRevisionParam end end rescue ActiveRecord::RecordNotFound render_404 rescue InvalidRevisionParam show_error_not_found end def show_error_not_found render_error :message => l(:error_scm_not_found), :status => 404 end # Handler for Redmine::Scm::Adapters::CommandFailed exception def show_error_command_failed(exception) render_error l(:error_scm_command_failed, exception.message) end def graph_commits_per_month(repository) @date_to = Date.today @date_from = @date_to << 11 @date_from = Date.civil(@date_from.year, @date_from.month, 1) 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, :conditions => ["commit_date BETWEEN ? AND ?", @date_from, @date_to]) changes_by_month = [0] * 12 changes_by_day.each {|c| changes_by_month[c.first.to_date.months_ago] += c.last } fields = [] 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)} graph = SVG::Graph::Bar.new( :height => 300, :width => 800, :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.to_a.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 # Remove email adress in usernames fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } graph = SVG::Graph::BarHorizontal.new( :height => 400, :width => 800, :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 class String def with_leading_slash starts_with?('/') ? self : "/#{self}" end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/roles_controller.rb 0000664 0000000 0000000 00000005116 11615721634 0030460 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class RolesController < ApplicationController layout 'admin' before_filter :require_admin verify :method => :post, :only => [ :destroy, :move ], :redirect_to => { :action => :index } def index @role_pages, @roles = paginate :roles, :per_page => 25, :order => 'builtin, position' render :action => "index", :layout => false if request.xhr? end def new # Prefills the form with 'Non member' role permissions @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions}) if request.post? && @role.save # workflow copy if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from])) @role.workflows.copy(copy_from) end flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index' else @permissions = @role.setable_permissions @roles = Role.find :all, :order => 'builtin, position' end end def edit @role = Role.find(params[:id]) if request.post? and @role.update_attributes(params[:role]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' else @permissions = @role.setable_permissions end end def destroy @role = Role.find(params[:id]) @role.destroy redirect_to :action => 'index' rescue flash[:error] = l(:error_can_not_remove_role) redirect_to :action => 'index' end def report @roles = Role.find(:all, :order => 'builtin, position') @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } if request.post? @roles.each do |role| role.permissions = params[:permissions][role.id.to_s] role.save end flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' end end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/search_controller.rb 0000664 0000000 0000000 00000007571 11615721634 0030610 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class SearchController < ApplicationController before_filter :find_optional_project helper :messages include MessagesHelper def index @question = params[:q] || "" @question.strip! @all_words = params[:all_words] || (params[:submit] ? false : true) @titles_only = !params[:titles_only].nil? projects_to_search = case params[:scope] when 'all' nil when 'my_projects' User.current.memberships.collect(&:project) when 'subprojects' @project ? (@project.self_and_descendants.active) : nil else @project end offset = nil begin; offset = params[:offset].to_time if params[:offset]; rescue; end # quick jump to an issue if @question.match(/^#?(\d+)$/) && Issue.visible.find_by_id($1.to_i) redirect_to :controller => "issues", :action => "show", :id => $1 return end @object_types = Redmine::Search.available_search_types.dup if projects_to_search.is_a? Project # don't search projects @object_types.delete('projects') # only show what the user is allowed to view @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)} end @scope = @object_types.select {|t| params[t]} @scope = @object_types if @scope.empty? # extract tokens from the question # eg. hello "bye bye" => ["hello", "bye bye"] @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')} # tokens must be at least 2 characters long @tokens = @tokens.uniq.select {|w| w.length > 1 } if !@tokens.empty? # no more than 5 tokens to search for @tokens.slice! 5..-1 if @tokens.size > 5 @results = [] @results_by_type = Hash.new {|h,k| h[k] = 0} limit = 10 @scope.each do |s| r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, :all_words => @all_words, :titles_only => @titles_only, :limit => (limit+1), :offset => offset, :before => params[:previous].nil?) @results += r @results_by_type[s] += c end @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime} if params[:previous].nil? @pagination_previous_date = @results[0].event_datetime if offset && @results[0] if @results.size > limit @pagination_next_date = @results[limit-1].event_datetime @results = @results[0, limit] end else @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] if @results.size > limit @pagination_previous_date = @results[-(limit)].event_datetime @results = @results[-(limit), limit] end end else @question = "" end render :layout => false if request.xhr? end private def find_optional_project return true unless params[:id] @project = Project.find(params[:id]) check_project_privacy rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/settings_controller.rb 0000664 0000000 0000000 00000004364 11615721634 0031200 0 ustar 00root root 0000000 0000000 # 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 SettingsController < ApplicationController layout 'admin' before_filter :require_admin def index edit render :action => 'edit' end def edit @notifiables = Redmine::Notifiable.all if request.post? && params[:settings] && params[:settings].is_a?(Hash) settings = (params[:settings] || {}).dup.symbolize_keys settings.each do |name, value| # remove blank values in array settings value.delete_if {|v| v.blank? } if value.is_a?(Array) Setting[name] = value end flash[:notice] = l(:notice_successful_update) redirect_to :action => 'edit', :tab => params[:tab] else @options = {} @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] } @deliveries = ActionMailer::Base.perform_deliveries @guessed_host_and_path = request.host_with_port.dup @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? Redmine::Themes.rescan end end def plugin @plugin = Redmine::Plugin.find(params[:id]) if request.post? Setting["plugin_#{@plugin.id}"] = params[:settings] flash[:notice] = l(:notice_successful_update) redirect_to :action => 'plugin', :id => @plugin.id else @partial = @plugin.settings[:partial] @settings = Setting["plugin_#{@plugin.id}"] end rescue Redmine::PluginNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/sys_controller.rb 0000664 0000000 0000000 00000004515 11615721634 0030154 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class SysController < ActionController::Base before_filter :check_enabled def projects p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') render :xml => p.to_xml(:include => :repository) end def create_project_repository project = Project.find(params[:id]) if project.repository render :nothing => true, :status => 409 else logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." project.repository = Repository.factory(params[:vendor], params[:repository]) if project.repository && project.repository.save render :xml => project.repository, :status => 201 else render :nothing => true, :status => 422 end end end def fetch_changesets projects = [] if params[:id] projects << Project.active.has_module(:repository).find(params[:id]) else projects = Project.active.has_module(:repository).find(:all, :include => :repository) end projects.each do |project| if project.repository project.repository.fetch_changesets end end render :nothing => true, :status => 200 rescue ActiveRecord::RecordNotFound render :nothing => true, :status => 404 end protected def check_enabled User.current = nil unless Setting.sys_api_enabled? && params[:key].to_s == Setting.sys_api_key render :text => 'Access denied. Repository management WS is disabled or key is invalid.', :status => 403 return false end end end time_entry_reports_controller.rb 0000664 0000000 0000000 00000022134 11615721634 0033211 0 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers class TimeEntryReportsController < ApplicationController menu_item :issues before_filter :find_optional_project before_filter :load_available_criterias helper :sort include SortHelper helper :issues helper :timelog include TimelogHelper helper :custom_fields include CustomFieldsHelper def report @criterias = params[:criterias] || [] @criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria} @criterias.uniq! @criterias = @criterias[0,3] @columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month' retrieve_date_range unless @criterias.empty? sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ') sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ') sql_condition = '' if @project.nil? sql_condition = Project.allowed_to_condition(User.current, :view_time_entries) elsif @issue.nil? sql_condition = @project.project_condition(Setting.display_subprojects_issues?) else sql_condition = "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" end sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours" sql << " FROM #{TimeEntry.table_name}" sql << time_report_joins sql << " WHERE" sql << " (%s) AND" % sql_condition sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)] sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on" @hours = ActiveRecord::Base.connection.select_all(sql) @hours.each do |row| case @columns when 'year' row['year'] = row['tyear'] when 'month' row['month'] = "#{row['tyear']}-#{row['tmonth']}" when 'week' row['week'] = "#{row['tyear']}-#{row['tweek']}" when 'day' row['day'] = "#{row['spent_on']}" end end @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} @periods = [] # Date#at_beginning_of_ not supported in Rails 1.2.x date_from = @from.to_time # 100 columns max while date_from <= @to.to_time && @periods.length < 100 case @columns when 'year' @periods << "#{date_from.year}" date_from = (date_from + 1.year).at_beginning_of_year when 'month' @periods << "#{date_from.year}-#{date_from.month}" date_from = (date_from + 1.month).at_beginning_of_month when 'week' @periods << "#{date_from.year}-#{date_from.to_date.cweek}" date_from = (date_from + 7.day).at_beginning_of_week when 'day' @periods << "#{date_from.to_date}" date_from = date_from + 1.day end end end respond_to do |format| format.html { render :layout => !request.xhr? } format.csv { send_data(report_to_csv(@criterias, @periods, @hours), :type => 'text/csv; header=present', :filename => 'timelog.csv') } end end private # TODO: duplicated in TimelogController def find_optional_project if !params[:issue_id].blank? @issue = Issue.find(params[:issue_id]) @project = @issue.project elsif !params[:project_id].blank? @project = Project.find(params[:project_id]) end deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) end # Retrieves the date range based on predefined ranges or specific from/to param dates # TODO: duplicated in TimelogController def retrieve_date_range @free_period = false @from, @to = nil, nil if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?) case params[:period].to_s when 'today' @from = @to = Date.today when 'yesterday' @from = @to = Date.today - 1 when 'current_week' @from = Date.today - (Date.today.cwday - 1)%7 @to = @from + 6 when 'last_week' @from = Date.today - 7 - (Date.today.cwday - 1)%7 @to = @from + 6 when '7_days' @from = Date.today - 7 @to = Date.today when 'current_month' @from = Date.civil(Date.today.year, Date.today.month, 1) @to = (@from >> 1) - 1 when 'last_month' @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 @to = (@from >> 1) - 1 when '30_days' @from = Date.today - 30 @to = Date.today when 'current_year' @from = Date.civil(Date.today.year, 1, 1) @to = Date.civil(Date.today.year, 12, 31) end elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end @free_period = true else # default end @from, @to = @to, @from if @from && @to && @from > @to @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) end def load_available_criterias @available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", :klass => Project, :label => :label_project}, 'version' => {:sql => "#{Issue.table_name}.fixed_version_id", :klass => Version, :label => :label_version}, 'category' => {:sql => "#{Issue.table_name}.category_id", :klass => IssueCategory, :label => :field_category}, 'member' => {:sql => "#{TimeEntry.table_name}.user_id", :klass => User, :label => :label_member}, 'tracker' => {:sql => "#{Issue.table_name}.tracker_id", :klass => Tracker, :label => :label_tracker}, 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", :klass => TimeEntryActivity, :label => :label_activity}, 'issue' => {:sql => "#{TimeEntry.table_name}.issue_id", :klass => Issue, :label => :label_issue} } # Add list and boolean custom fields as available criterias custom_fields = (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields) custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf| @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = #{Issue.table_name}.id)", :format => cf.field_format, :label => cf.name} end if @project # Add list and boolean time entry custom fields TimeEntryCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'TimeEntry' AND c.customized_id = #{TimeEntry.table_name}.id)", :format => cf.field_format, :label => cf.name} end # Add list and boolean time entry activity custom fields TimeEntryActivityCustomField.find(:all).select {|cf| %w(list bool).include? cf.field_format }.each do |cf| @available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM #{CustomValue.table_name} c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Enumeration' AND c.customized_id = #{TimeEntry.table_name}.activity_id)", :format => cf.field_format, :label => cf.name} end call_hook(:controller_timelog_available_criterias, { :available_criterias => @available_criterias, :project => @project }) @available_criterias end def time_report_joins sql = '' sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" # TODO: rename hook call_hook(:controller_timelog_time_report_joins, {:sql => sql} ) sql end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/timelog_controller.rb 0000664 0000000 0000000 00000024364 11615721634 0031002 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2010 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 TimelogController < ApplicationController menu_item :issues before_filter :find_project, :only => [:new, :create] before_filter :find_time_entry, :only => [:show, :edit, :update, :destroy] before_filter :authorize, :except => [:index] before_filter :find_optional_project, :only => [:index] accept_key_auth :index, :show, :create, :update, :destroy helper :sort include SortHelper helper :issues include TimelogHelper helper :custom_fields include CustomFieldsHelper def index sort_init 'spent_on', 'desc' sort_update 'spent_on' => 'spent_on', 'user' => 'user_id', 'activity' => 'activity_id', 'project' => "#{Project.table_name}.name", 'issue' => 'issue_id', 'hours' => 'hours' cond = ARCondition.new if @project.nil? cond << Project.allowed_to_condition(User.current, :view_time_entries) elsif @issue.nil? cond << @project.project_condition(Setting.display_subprojects_issues?) else cond << "#{Issue.table_name}.root_id = #{@issue.root_id} AND #{Issue.table_name}.lft >= #{@issue.lft} AND #{Issue.table_name}.rgt <= #{@issue.rgt}" end retrieve_date_range cond << ['spent_on BETWEEN ? AND ?', @from, @to] TimeEntry.visible_by(User.current) do respond_to do |format| format.html { # Paginate results @entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions) @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] @entries = TimeEntry.find(:all, :include => [:project, :activity, :user, {:issue => :tracker}], :conditions => cond.conditions, :order => sort_clause, :limit => @entry_pages.items_per_page, :offset => @entry_pages.current.offset) @total_hours = TimeEntry.sum(:hours, :include => [:project, :issue], :conditions => cond.conditions).to_f render :layout => !request.xhr? } format.api { @entry_count = TimeEntry.count(:include => [:project, :issue], :conditions => cond.conditions) @entry_pages = Paginator.new self, @entry_count, per_page_option, params['page'] @entries = TimeEntry.find(:all, :include => [:project, :activity, :user, {:issue => :tracker}], :conditions => cond.conditions, :order => sort_clause, :limit => @entry_pages.items_per_page, :offset => @entry_pages.current.offset) } format.atom { entries = TimeEntry.find(:all, :include => [:project, :activity, :user, {:issue => :tracker}], :conditions => cond.conditions, :order => "#{TimeEntry.table_name}.created_on DESC", :limit => Setting.feeds_limit.to_i) render_feed(entries, :title => l(:label_spent_time)) } format.csv { # Export all entries @entries = TimeEntry.find(:all, :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], :conditions => cond.conditions, :order => sort_clause) send_data(entries_to_csv(@entries), :type => 'text/csv; header=present', :filename => 'timelog.csv') } end end end def show respond_to do |format| # TODO: Implement html response format.html { render :nothing => true, :status => 406 } format.api end end def new @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry.attributes = params[:time_entry] call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) render :action => 'edit' end verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) @time_entry.attributes = params[:time_entry] call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) if @time_entry.save respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) redirect_back_or_default :action => 'index', :project_id => @time_entry.project } format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } end else respond_to do |format| format.html { render :action => 'edit' } format.api { render_validation_errors(@time_entry) } end end end def edit @time_entry.attributes = params[:time_entry] call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def update @time_entry.attributes = params[:time_entry] call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) if @time_entry.save respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) redirect_back_or_default :action => 'index', :project_id => @time_entry.project } format.api { head :ok } end else respond_to do |format| format.html { render :action => 'edit' } format.api { render_validation_errors(@time_entry) } end end end verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed } def destroy if @time_entry.destroy && @time_entry.destroyed? respond_to do |format| format.html { flash[:notice] = l(:notice_successful_delete) redirect_to :back } format.api { head :ok } end else respond_to do |format| format.html { flash[:error] = l(:notice_unable_delete_time_entry) redirect_to :back } format.api { render_validation_errors(@time_entry) } end end rescue ::ActionController::RedirectBackError redirect_to :action => 'index', :project_id => @time_entry.project end private def find_time_entry @time_entry = TimeEntry.find(params[:id]) unless @time_entry.editable_by?(User.current) render_403 return false end @project = @time_entry.project rescue ActiveRecord::RecordNotFound render_404 end def find_project if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? @issue = Issue.find(issue_id) @project = @issue.project elsif (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? @project = Project.find(project_id) else render_404 return false end rescue ActiveRecord::RecordNotFound render_404 end def find_optional_project if !params[:issue_id].blank? @issue = Issue.find(params[:issue_id]) @project = @issue.project elsif !params[:project_id].blank? @project = Project.find(params[:project_id]) end deny_access unless User.current.allowed_to?(:view_time_entries, @project, :global => true) end # Retrieves the date range based on predefined ranges or specific from/to param dates def retrieve_date_range @free_period = false @from, @to = nil, nil if params[:period_type] == '1' || (params[:period_type].nil? && !params[:period].nil?) case params[:period].to_s when 'today' @from = @to = Date.today when 'yesterday' @from = @to = Date.today - 1 when 'current_week' @from = Date.today - (Date.today.cwday - 1)%7 @to = @from + 6 when 'last_week' @from = Date.today - 7 - (Date.today.cwday - 1)%7 @to = @from + 6 when '7_days' @from = Date.today - 7 @to = Date.today when 'current_month' @from = Date.civil(Date.today.year, Date.today.month, 1) @to = (@from >> 1) - 1 when 'last_month' @from = Date.civil(Date.today.year, Date.today.month, 1) << 1 @to = (@from >> 1) - 1 when '30_days' @from = Date.today - 30 @to = Date.today when 'current_year' @from = Date.civil(Date.today.year, 1, 1) @to = Date.civil(Date.today.year, 12, 31) end elsif params[:period_type] == '2' || (params[:period_type].nil? && (!params[:from].nil? || !params[:to].nil?)) begin; @from = params[:from].to_s.to_date unless params[:from].blank?; rescue; end begin; @to = params[:to].to_s.to_date unless params[:to].blank?; rescue; end @free_period = true else # default end @from, @to = @to, @from if @from && @to && @from > @to @from ||= (TimeEntry.earilest_date_for_project(@project) || Date.today) @to ||= (TimeEntry.latest_date_for_project(@project) || Date.today) end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/trackers_controller.rb 0000664 0000000 0000000 00000004146 11615721634 0031154 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2009 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class TrackersController < ApplicationController layout 'admin' before_filter :require_admin verify :method => :post, :only => :destroy, :redirect_to => { :action => :index } def index @tracker_pages, @trackers = paginate :trackers, :per_page => 10, :order => 'position' render :action => "index", :layout => false if request.xhr? end def new @tracker = Tracker.new(params[:tracker]) if request.post? and @tracker.save # workflow copy if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from])) @tracker.workflows.copy(copy_from) end flash[:notice] = l(:notice_successful_create) redirect_to :action => 'index' return end @trackers = Tracker.find :all, :order => 'position' @projects = Project.find(:all) end def edit @tracker = Tracker.find(params[:id]) if request.post? and @tracker.update_attributes(params[:tracker]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'index' return end @projects = Project.find(:all) end def destroy @tracker = Tracker.find(params[:id]) unless @tracker.issues.empty? flash[:error] = l(:error_can_not_delete_tracker) else @tracker.destroy end redirect_to :action => 'index' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/users_controller.rb 0000664 0000000 0000000 00000017746 11615721634 0030511 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2010 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 UsersController < ApplicationController layout 'admin' before_filter :require_admin, :except => :show before_filter :find_user, :only => [:show, :edit, :update, :edit_membership, :destroy_membership] accept_key_auth :index, :show, :create, :update helper :sort include SortHelper helper :custom_fields include CustomFieldsHelper def index sort_init 'login', 'asc' sort_update %w(login firstname lastname mail admin created_on last_login_on) case params[:format] when 'xml', 'json' @offset, @limit = api_offset_and_limit else @limit = per_page_option end @status = params[:status] ? params[:status].to_i : 1 c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) unless params[:name].blank? name = "%#{params[:name].strip.downcase}%" c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ? OR LOWER(mail) LIKE ?", name, name, name, name] end @user_count = User.count(:conditions => c.conditions) @user_pages = Paginator.new self, @user_count, @limit, params['page'] @offset ||= @user_pages.current.offset @users = User.find :all, :order => sort_clause, :conditions => c.conditions, :limit => @limit, :offset => @offset respond_to do |format| format.html { render :layout => !request.xhr? } format.api end end def show # show projects based on current user visibility @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current)) events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) @events_by_day = events.group_by(&:event_date) unless User.current.admin? if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) render_404 return end end respond_to do |format| format.html { render :layout => 'base' } format.api end end def new @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) @auth_sources = AuthSource.find(:all) end verify :method => :post, :only => :create, :render => {:nothing => true, :status => :method_not_allowed } def create @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) @user.safe_attributes = params[:user] @user.admin = params[:user][:admin] || false @user.login = params[:user][:login] @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] if @user.change_password_allowed? # TODO: Similar to My#account @user.pref.attributes = params[:pref] @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') if @user.save @user.pref.save @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) Mailer.deliver_account_information(@user, params[:user][:password]) if params[:send_information] respond_to do |format| format.html { flash[:notice] = l(:notice_successful_create) redirect_to(params[:continue] ? {:controller => 'users', :action => 'new'} : {:controller => 'users', :action => 'edit', :id => @user} ) } format.api { render :action => 'show', :status => :created, :location => user_url(@user) } end else @auth_sources = AuthSource.find(:all) # Clear password input @user.password = @user.password_confirmation = nil respond_to do |format| format.html { render :action => 'new' } format.api { render_validation_errors(@user) } end end end def edit @auth_sources = AuthSource.find(:all) @membership ||= Member.new end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } def update @user.admin = params[:user][:admin] if params[:user][:admin] @user.login = params[:user][:login] if params[:user][:login] @user.safe_attributes = params[:user] if params[:user][:password].present? && @user.change_password_allowed? @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] end # Was the account actived ? (do it before User#save clears the change) was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE]) # TODO: Similar to My#account @user.pref.attributes = params[:pref] @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') if @user.save @user.pref.save @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) if was_activated Mailer.deliver_account_activated(@user) elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.change_password_allowed? Mailer.deliver_account_information(@user, params[:user][:password]) end respond_to do |format| format.html { flash[:notice] = l(:notice_successful_update) redirect_to :back } format.api { head :ok } end else @auth_sources = AuthSource.find(:all) @membership ||= Member.new # Clear password input @user.password = @user.password_confirmation = nil respond_to do |format| format.html { render :action => :edit } format.api { render_validation_errors(@user) } end end rescue ::ActionController::RedirectBackError redirect_to :controller => 'users', :action => 'edit', :id => @user end def edit_membership @membership = Member.edit_membership(params[:membership_id], params[:membership], @user) @membership.save if request.post? respond_to do |format| if @membership.valid? format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships' page.visual_effect(:highlight, "member-#{@membership.id}") } } else format.js { render(:update) {|page| page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) } } end end end def destroy_membership @membership = Member.find(params[:membership_id]) if request.post? && @membership.deletable? @membership.destroy end respond_to do |format| format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } format.js { render(:update) {|page| page.replace_html "tab-content-memberships", :partial => 'users/memberships'} } end end private def find_user if params[:id] == 'current' require_login || return @user = User.current else @user = User.find(params[:id]) end rescue ActiveRecord::RecordNotFound render_404 end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/versions_controller.rb 0000664 0000000 0000000 00000014141 11615721634 0031202 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class VersionsController < ApplicationController menu_item :roadmap model_object Version before_filter :find_model_object, :except => [:index, :new, :create, :close_completed] before_filter :find_project_from_association, :except => [:index, :new, :create, :close_completed] before_filter :find_project, :only => [:index, :new, :create, :close_completed] before_filter :authorize helper :custom_fields helper :projects def index @trackers = @project.trackers.find(:all, :order => 'position') retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] @versions = @project.shared_versions || [] @versions += @project.rolled_up_versions.visible if @with_subprojects @versions = @versions.uniq.sort @versions.reject! {|version| version.closed? || version.completed? } unless params[:completed] @issues_by_version = {} unless @selected_tracker_ids.empty? @versions.each do |version| issues = version.fixed_issues.visible.find(:all, :include => [:project, :status, :tracker, :priority], :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids}, :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") @issues_by_version[version] = issues end end @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} end def show @issues = @version.fixed_issues.visible.find(:all, :include => [:status, :tracker, :priority], :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") end def new @version = @project.versions.build if params[:version] attributes = params[:version].dup attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) @version.attributes = attributes end end def create # TODO: refactor with code above in #new @version = @project.versions.build if params[:version] attributes = params[:version].dup attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) @version.attributes = attributes end if request.post? if @version.save respond_to do |format| format.html do flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end format.js do # IE doesn't support the replace_html rjs method for select box options render(:update) {|page| page.replace "issue_fixed_version_id", content_tag('select', '' + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') } end end else respond_to do |format| format.html { render :action => 'new' } format.js do render(:update) {|page| page.alert(@version.errors.full_messages.join('\n')) } end end end end end def edit end def update if request.put? && params[:version] attributes = params[:version].dup attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) if @version.update_attributes(attributes) flash[:notice] = l(:notice_successful_update) redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project else respond_to do |format| format.html { render :action => 'edit' } end end end end def close_completed if request.put? @project.close_completed_versions end redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end def destroy if @version.fixed_issues.empty? @version.destroy redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project else flash[:error] = l(:notice_unable_delete_version) redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end end def status_by respond_to do |format| format.html { render :action => 'show' } format.js { render(:update) {|page| page.replace_html 'status_by', render_issue_status_by(@version, params[:status_by])} } end end private def find_project @project = Project.find(params[:project_id]) rescue ActiveRecord::RecordNotFound render_404 end def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil) if ids = params[:tracker_ids] @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } else @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s } end end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/watchers_controller.rb 0000664 0000000 0000000 00000006554 11615721634 0031163 0 ustar 00root root 0000000 0000000 # 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 WatchersController < ApplicationController before_filter :find_project before_filter :require_login, :check_project_privacy, :only => [:watch, :unwatch] before_filter :authorize, :only => [:new, :destroy] verify :method => :post, :only => [ :watch, :unwatch ], :render => { :nothing => true, :status => :method_not_allowed } def watch if @watched.respond_to?(:visible?) && !@watched.visible?(User.current) render_403 else set_watcher(User.current, true) end end def unwatch set_watcher(User.current, false) end def new @watcher = Watcher.new(params[:watcher]) @watcher.watchable = @watched @watcher.save if request.post? respond_to do |format| format.html { redirect_to :back } format.js do render :update do |page| page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} end end end rescue ::ActionController::RedirectBackError render :text => 'Watcher added.', :layout => true end def destroy @watched.set_watcher(User.find(params[:user_id]), false) if request.post? respond_to do |format| format.html { redirect_to :back } format.js do render :update do |page| page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} end end end end private def find_project klass = Object.const_get(params[:object_type].camelcase) return false unless klass.respond_to?('watched_by') @watched = klass.find(params[:object_id]) @project = @watched.project rescue render_404 end def set_watcher(user, watching) @watched.set_watcher(user, watching) if params[:replace].present? if params[:replace].is_a? Array replace_ids = params[:replace] else replace_ids = [params[:replace]] end else replace_ids = ['watcher'] end respond_to do |format| format.html { redirect_to :back } format.js do render(:update) do |page| replace_ids.each do |replace_id| case replace_id when 'watchers' page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} else page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids) end end end end end rescue ::ActionController::RedirectBackError render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/welcome_controller.rb 0000664 0000000 0000000 00000002103 11615721634 0030760 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class WelcomeController < ApplicationController caches_action :robots def index @news = News.latest User.current @projects = Project.latest User.current end def robots @projects = Project.all_public.active render :layout => false, :content_type => 'text/plain' end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/wiki_controller.rb 0000664 0000000 0000000 00000023711 11615721634 0030300 0 ustar 00root root 0000000 0000000 # 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 'diff' # The WikiController follows the Rails REST controller pattern but with # a few differences # # * index - shows a list of WikiPages grouped by page or date # * new - not used # * create - not used # * show - will also show the form for creating a new wiki page # * edit - used to edit an existing or new page # * update - used to save a wiki page update to the database, including new pages # * destroy - normal # # Other member and collection methods are also used # # TODO: still being worked on class WikiController < ApplicationController default_search_scope :wiki_pages before_filter :find_wiki, :authorize before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy] verify :method => :post, :only => [:protect], :redirect_to => { :action => :show } helper :attachments include AttachmentsHelper helper :watchers # List of pages, sorted alphabetically and by parent (hierarchy) def index load_pages_grouped_by_date_without_content end # display a page (in editing mode if it doesn't exist) def show page_title = params[:id] @page = @wiki.find_or_new_page(page_title) if @page.new_record? if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? edit render :action => 'edit' else render_404 end return end if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) # Redirects user to the current version if he's not allowed to view previous versions redirect_to :version => nil return end @content = @page.content_for_version(params[:version]) if User.current.allowed_to?(:export_wiki_pages, @project) if params[:format] == 'html' export = render_to_string :action => 'export', :layout => false send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") return elsif params[:format] == 'txt' send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") return end end @editable = editable? render :action => 'show' end # edit an existing page or a new one def edit @page = @wiki.find_or_new_page(params[:id]) return render_403 unless editable? @page.content = WikiContent.new(:page => @page) if @page.new_record? @content = @page.content_for_version(params[:version]) @content.text = initial_page_content(@page) if @content.text.blank? # don't keep previous comment @content.comments = nil # To prevent StaleObjectError exception when reverting to a previous version @content.version = @page.content.version rescue ActiveRecord::StaleObjectError # Optimistic locking exception flash[:error] = l(:notice_locking_conflict) end verify :method => :put, :only => :update, :render => {:nothing => true, :status => :method_not_allowed } # Creates a new page or updates an existing one def update @page = @wiki.find_or_new_page(params[:id]) return render_403 unless editable? @page.content = WikiContent.new(:page => @page) if @page.new_record? @content = @page.content_for_version(params[:version]) @content.text = initial_page_content(@page) if @content.text.blank? # don't keep previous comment @content.comments = nil if !@page.new_record? && params[:content].present? && @content.text == params[:content][:text] attachments = Attachment.attach_files(@page, params[:attachments]) render_attachment_warning_if_needed(@page) # don't save if text wasn't changed redirect_to :action => 'show', :project_id => @project, :id => @page.title return end @content.attributes = params[:content] @content.author = User.current # if page is new @page.save will also save content, but not if page isn't a new record if (@page.new_record? ? @page.save : @content.save) attachments = Attachment.attach_files(@page, params[:attachments]) render_attachment_warning_if_needed(@page) call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) redirect_to :action => 'show', :project_id => @project, :id => @page.title else render :action => 'edit' end rescue ActiveRecord::StaleObjectError # Optimistic locking exception flash[:error] = l(:notice_locking_conflict) end # rename a page def rename return render_403 unless editable? @page.redirect_existing_links = true # used to display the *original* title if some AR validation errors occur @original_title = @page.pretty_title if request.post? && @page.update_attributes(params[:wiki_page]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'show', :project_id => @project, :id => @page.title end end def protect @page.update_attribute :protected, params[:protected] redirect_to :action => 'show', :project_id => @project, :id => @page.title end # show page history def history @version_count = @page.content.versions.count @version_pages = Paginator.new self, @version_count, per_page_option, params['p'] # don't load text @versions = @page.content.versions.find :all, :select => "id, author_id, comments, updated_on, version", :order => 'version DESC', :limit => @version_pages.items_per_page + 1, :offset => @version_pages.current.offset render :layout => false if request.xhr? end def diff @diff = @page.diff(params[:version], params[:version_from]) render_404 unless @diff end def annotate @annotate = @page.annotate(params[:version]) render_404 unless @annotate end verify :method => :delete, :only => [:destroy], :redirect_to => { :action => :show } # Removes a wiki page and its history # Children can be either set as root pages, removed or reassigned to another parent page def destroy return render_403 unless editable? @descendants_count = @page.descendants.size if @descendants_count > 0 case params[:todo] when 'nullify' # Nothing to do when 'destroy' # Removes all its descendants @page.descendants.each(&:destroy) when 'reassign' # Reassign children to another parent page reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) return unless reassign_to @page.children.each do |child| child.update_attribute(:parent, reassign_to) end else @reassignable_to = @wiki.pages - @page.self_and_descendants return end end @page.destroy redirect_to :action => 'index', :project_id => @project end # Export wiki to a single html file def export if User.current.allowed_to?(:export_wiki_pages, @project) @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") else redirect_to :action => 'show', :project_id => @project, :id => nil end end def date_index load_pages_grouped_by_date_without_content end def preview page = @wiki.find_page(params[:id]) # page is nil when previewing a new page return render_403 unless page.nil? || editable?(page) if page @attachements = page.attachments @previewed = page.content end @text = params[:content][:text] render :partial => 'common/preview' end def add_attachment return render_403 unless editable? attachments = Attachment.attach_files(@page, params[:attachments]) render_attachment_warning_if_needed(@page) redirect_to :action => 'show', :id => @page.title, :project_id => @project end private def find_wiki @project = Project.find(params[:project_id]) @wiki = @project.wiki render_404 unless @wiki rescue ActiveRecord::RecordNotFound render_404 end # Finds the requested page and returns a 404 error if it doesn't exist def find_existing_page @page = @wiki.find_page(params[:id]) render_404 if @page.nil? end # Returns true if the current user is allowed to edit the page, otherwise false def editable?(page = @page) page.editable_by?(User.current) end # Returns the default content of a new wiki page def initial_page_content(page) helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) extend helper unless self.instance_of?(helper) helper.instance_method(:initial_page_content).bind(self).call(page) end # eager load information about last updates, without loading text def load_pages_grouped_by_date_without_content @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' @pages_by_date = @pages.group_by {|p| p.updated_on.to_date} @pages_by_parent_id = @pages.group_by(&:parent_id) end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/wikis_controller.rb 0000664 0000000 0000000 00000002651 11615721634 0030463 0 ustar 00root root 0000000 0000000 # 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 WikisController < ApplicationController menu_item :settings before_filter :find_project, :authorize # Create or update a project's wiki def edit @wiki = @project.wiki || Wiki.new(:project => @project) @wiki.attributes = params[:wiki] @wiki.save if request.post? render(:update) {|page| page.replace_html "tab-content-wiki", :partial => 'projects/settings/wiki'} end # Delete a project's wiki def destroy if request.post? && params[:confirm] && @project.wiki @project.wiki.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'wiki' end end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/controllers/workflows_controller.rb 0000664 0000000 0000000 00000006422 11615721634 0031372 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2008 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 WorkflowsController < ApplicationController layout 'admin' before_filter :require_admin before_filter :find_roles before_filter :find_trackers def index @workflow_counts = Workflow.count_by_tracker_and_role end def edit @role = Role.find_by_id(params[:role_id]) @tracker = Tracker.find_by_id(params[:tracker_id]) if request.post? Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) (params[:issue_status] || []).each { |old, news| news.each { |new| @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) } } if @role.save flash[:notice] = l(:notice_successful_update) redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker end end @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) if @tracker && @used_statuses_only && @tracker.issue_statuses.any? @statuses = @tracker.issue_statuses end @statuses ||= IssueStatus.find(:all, :order => 'position') end def copy if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' @source_tracker = nil else @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) end if params[:source_role_id].blank? || params[:source_role_id] == 'any' @source_role = nil else @source_role = Role.find_by_id(params[:source_role_id].to_i) end @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) if request.post? if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) flash.now[:error] = l(:error_workflow_copy_source) elsif @target_trackers.nil? || @target_roles.nil? flash.now[:error] = l(:error_workflow_copy_target) else Workflow.copy(@source_tracker, @source_role, @target_trackers, @target_roles) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'copy', :source_tracker_id => @source_tracker, :source_role_id => @source_role end end end private def find_roles @roles = Role.find(:all, :order => 'builtin, position') end def find_trackers @trackers = Tracker.find(:all, :order => 'position') end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/helpers/ 0000775 0000000 0000000 00000000000 11615721634 0023635 5 ustar 00root root 0000000 0000000 ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/helpers/account_helper.rb 0000664 0000000 0000000 00000001461 11615721634 0027157 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module AccountHelper end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/helpers/admin_helper.rb 0000664 0000000 0000000 00000001720 11615721634 0026611 0 ustar 00root root 0000000 0000000 # redMine - project management software # Copyright (C) 2006 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module AdminHelper def project_status_options_for_select(selected) options_for_select([[l(:label_all), ''], [l(:status_active), 1]], selected) end end ohr-support-aa2c444acf5e8a79db5875d9167ed2dbedd424bd/app/helpers/application_helper.rb 0000664 0000000 0000000 00000106441 11615721634 0030032 0 ustar 00root root 0000000 0000000 # Redmine - project management software # Copyright (C) 2006-2010 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 'forwardable' require 'cgi' module ApplicationHelper include Redmine::WikiFormatting::Macros::Definitions include Redmine::I18n include GravatarHelper::PublicMethods extend Forwardable def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter # Return true if user is authorized for controller/action, otherwise false def authorize_for(controller, action) User.current.allowed_to?({:controller => controller, :action => action}, @project) end # Display a link if user is authorized # # @param [String] name Anchor text (passed to link_to) # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized # @param [optional, Hash] html_options Options passed to link_to # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to 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] || params[:controller], options[:action]) end # Display a link to remote if user is authorized def link_to_remote_if_authorized(name, options = {}, html_options = nil) url = options[:url] || {} link_to_remote(name, options, html_options) if authorize_for(url[:controller] || params[:controller], url[:action]) end # Displays a link to user's account page if active def link_to_user(user, options={}) if user.is_a?(User) name = h(user.name(options[:format])) if user.active? link_to name, :controller => 'users', :action => 'show', :id => user else name end else h(user.to_s) end end # Show a sorted linkified (if active) comma-joined list of users def list_users(users, options={}) users.sort.collect{|u| link_to_user(u, options)}.join(", ") end # Displays a link to +issue+ with its subject. # Examples: # # link_to_issue(issue) # => Defect #6: This is the subject # link_to_issue(issue, :truncate => 6) # => Defect #6: This i... # link_to_issue(issue, :subject => false) # => Defect #6 # link_to_issue(issue, :project => true) # => Foo - Defect #6 # def link_to_issue(issue, options={}) title = nil subject = nil if options[:subject] == false title = truncate(issue.subject, :length => 60) else subject = issue.subject if options[:truncate] subject = truncate(subject, :length => options[:truncate]) end end s = link_to "#{h(issue.tracker)} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, :class => issue.css_classes, :title => title s << ": #{h subject}" if subject s = "#{h issue.project} - " + s if options[:project] s end # Generates a link to an attachment. # Options: # * :text - Link text (default to attachment filename) # * :download - Force download (default: false) def link_to_attachment(attachment, options={}) text = options.delete(:text) || attachment.filename action = options.delete(:download) ? 'download' : 'show' link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options) end # Generates a link to a SCM revision # Options: # * :text - Link text (default to the formatted revision) def link_to_revision(revision, project, options={}) text = options.delete(:text) || format_revision(revision) rev = revision.respond_to?(:identifier) ? revision.identifier : revision link_to(h(text), {:controller => 'repositories', :action => 'revision', :id => project, :rev => rev}, :title => l(:label_revision_id, format_revision(revision))) end # Generates a link to a message def link_to_message(message, options={}, html_options = nil) link_to( h(truncate(message.subject, :length => 60)), { :controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root, :r => (message.parent_id && message.id), :anchor => (message.parent_id ? "message-#{message.id}" : nil) }.merge(options), html_options ) end # Generates a link to a project if active # Examples: # # link_to_project(project) # => link to the specified project overview # link_to_project(project, :action=>'settings') # => link to project settings # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) # def link_to_project(project, options={}, html_options = nil) if project.active? url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) link_to(h(project), url, html_options) else h(project) end end def toggle_link(name, id, options={}) onclick = "Element.toggle('#{id}'); " onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ") onclick << "return false;" link_to(name, "#", :onclick => onclick) end def image_to_function(name, function, html_options = {}) html_options.symbolize_keys! tag(:input, html_options.merge({ :type => "image", :src => image_path(name), :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" })) end def prompt_to_remote(name, text, param, url, html_options = {}) html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;" link_to name, {}, html_options end def format_activity_title(text) h(truncate_single_line(text, :length => 100)) end def format_activity_day(date) date == Date.today ? l(:label_today).titleize : format_date(date) end def format_activity_description(text) h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
' + l(:label_export_to)) yield Redmine::Views::OtherFormatsBuilder.new(self) concat('
') end def page_header_title if @project.nil? || @project.new_record? h(Setting.app_title) else b = [] ancestors = (@project.root? ? [] : @project.ancestors.visible) if ancestors.any? root = ancestors.shift b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') if ancestors.size > 2 b << '…' ancestors = ancestors[-2, 2] end b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } end b << h(@project) b.join(' » ') end end def html_title(*args) if args.empty? title = [] title << h(@project.name) if @project title += @html_title if @html_title title << Setting.app_title title.select {|t| !t.blank? }.join(' - ') else @html_title ||= [] @html_title += args end end # Returns the theme, controller name, and action as css classes for the # HTML body. def body_css_classes css = [] if theme = Redmine::Themes.theme(Setting.ui_theme) css << 'theme-' + theme.name end css << 'controller-' + params[:controller] css << 'action-' + params[:action] css.join(' ') end def accesskey(s) Redmine::AccessKeys.key_for s end # Formats text according to system settings. # 2 ways to call this method: # * with a String: textilizable(text, options) # * with an object and one of its attribute: textilizable(issue, :description, options) def textilizable(*args) options = args.last.is_a?(Hash) ? args.pop : {} case args.size when 1 obj = options[:object] text = args.shift when 2 obj = args.shift attr = args.shift text = obj.send(attr).to_s else raise ArgumentError, 'invalid arguments to textilizable' end return '' if text.blank? project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) only_path = options.delete(:only_path) == false ? false : true text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) { |macro, args| exec_macro(macro, obj, args) } @parsed_headings = [] text = parse_non_pre_blocks(text) do |text| [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links, :parse_headings].each do |method_name| send method_name, text, project, obj, attr, only_path, options end end if @parsed_headings.any? replace_toc(text, @parsed_headings) end text end def parse_non_pre_blocks(text) s = StringScanner.new(text) tags = [] parsed = '' while !s.eos? s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) text, full_tag, closing, tag = s[1], s[2], s[3], s[4] if tags.empty? yield text end parsed << text if tag if closing if tags.last == tag.downcase tags.pop end else tags << tag.downcase end parsed << full_tag end end # Close any non closing tags while tag = tags.pop parsed << "#{tag}>" end parsed end def parse_inline_attachments(text, project, obj, attr, only_path, options) # when using an image link, try to use an attachment, if possible if options[:attachments] || (obj && obj.respond_to?(:attachments)) attachments = nil text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| filename, ext, alt, alttext = $1.downcase, $2, $3, $4 attachments ||= (options[:attachments] || obj.attachments).sort_by(&:created_on).reverse # search for the picture in attachments if found = attachments.detect { |att| att.filename.downcase == filename } image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found desc = found.description.to_s.gsub('"', '') if !desc.blank? && alttext.blank? alt = " title=\"#{desc}\" alt=\"#{desc}\"" end "src=\"#{image_url}\"#{alt}" else m end end end end # Wiki links # # Examples: # [[mypage]] # [[mypage|mytext]] # wiki links can refer other project wikis, using project name or identifier: # [[project:]] -> wiki starting page # [[project:|mytext]] # [[project:mypage]] # [[project:mypage|mytext]] def parse_wiki_links(text, project, obj, attr, only_path, options) text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| link_project = project esc, all, page, title = $1, $2, $3, $5 if esc.nil? if page =~ /^([^\:]+)\:(.*)$/ link_project = Project.find_by_identifier($1) || Project.find_by_name($1) page = $2 title ||= $1 if page.blank? end if link_project && link_project.wiki # extract anchor anchor = nil if page =~ /^(.+?)\#(.+)$/ page, anchor = $1, $2 end # check if page exists wiki_page = link_project.wiki.find_page(page) url = case options[:wiki_links] when :local; "#{title}.html" when :anchor; "##{title}" # used for single-file wiki export else wiki_page_id = page.present? ? Wiki.titleize(page) : nil url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, :id => wiki_page_id, :anchor => anchor) end link_to(h(title || page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) else # project or wiki doesn't exist all end else all end end end # Redmine links # # Examples: # Issues: # #52 -> Link to issue #52 # Changesets: # r52 -> Link to revision 52 # commit:a85130f -> Link to scmid starting with a85130f # Documents: # document#17 -> Link to document with id 17 # document:Greetings -> Link to the document with title "Greetings" # document:"Some document" -> Link to the document with title "Some document" # Versions: # version#3 -> Link to version with id 3 # version:1.0.0 -> Link to version named "1.0.0" # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" # Attachments: # attachment:file.zip -> Link to the attachment of the current object named file.zip # Source files: # source:some/file -> Link to the file located at /some/file in the project's repository # source:some/file@52 -> Link to the file's revision 52 # source:some/file#L120 -> Link to line 120 of the file # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 # export:some/file -> Force the download of the file # Forum messages: # message#1218 -> Link to message with id 1218 # # Links can refer other objects from other projects, using project identifier: # identifier:r52 # identifier:document:"Some document" # identifier:version:1.0.0 # identifier:source:some/file def parse_redmine_links(text, project, obj, attr, only_path, options) text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-]+):)?(attachment|document|version|commit|source|export|message|project)?((#|r)(\d+)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]]\W)|,|\s|\]|<|$)}) do |m| leading, esc, project_prefix, project_identifier, prefix, sep, identifier = $1, $2, $3, $4, $5, $7 || $9, $8 || $10 link = nil if project_identifier project = Project.visible.find_by_identifier(project_identifier) end if esc.nil? if prefix.nil? && sep == 'r' # project.changesets.visible raises an SQL error because of a double join on repositories if project && project.repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(project.repository.id, identifier)) link = link_to(h("#{project_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.revision}, :class => 'changeset', :title => truncate_single_line(changeset.comments, :length => 100)) end elsif sep == '#' oid = identifier.to_i case prefix when nil if issue = Issue.visible.find_by_id(oid, :include => :status) link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid}, :class => issue.css_classes, :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") end when 'document' if document = Document.visible.find_by_id(oid) link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, :class => 'document' end when 'version' if version = Version.visible.find_by_id(oid) link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, :class => 'version' end when 'message' if message = Message.visible.find_by_id(oid, :include => :parent) link = link_to_message(message, {:only_path => only_path}, :class => 'message') end when 'project' if p = Project.visible.find_by_id(oid) link = link_to_project(p, {:only_path => only_path}, :class => 'project') end end elsif sep == ':' # removes the double quotes if any name = identifier.gsub(%r{^"(.*)"$}, "\\1") case prefix when 'document' if project && document = project.documents.visible.find_by_title(name) link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, :class => 'document' end when 'version' if project && version = project.versions.visible.find_by_name(name) link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, :class => 'version' end when 'commit' if project && project.repository && (changeset = Changeset.visible.find(:first, :conditions => ["repository_id = ? AND scmid LIKE ?", project.repository.id, "#{name}%"])) link = link_to h("#{project_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :rev => changeset.identifier}, :class => 'changeset', :title => truncate_single_line(h(changeset.comments), :length => 100) end when 'source', 'export' if project && project.repository && User.current.allowed_to?(:browse_repository, project) name =~ %r{^[/\\]*(.*?)(@([0-9a-f]+))?(#(L\d+))?$} path, rev, anchor = $1, $3, $5 link = link_to h("#{project_prefix}#{prefix}:#{name}"), {:controller => 'repositories', :action => 'entry', :id => project, :path => to_path_param(path), :rev => rev, :anchor => anchor, :format => (prefix == 'export' ? 'raw' : nil)}, :class => (prefix == 'export' ? 'source download' : 'source') end when 'attachment' attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) if attachments && attachment = attachments.detect {|a| a.filename == name } link = link_to h(attachment.filename), {:only_path => only_path, :controller => 'attachments', :action => 'download', :id => attachment}, :class => 'attachment' end when 'project' if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}]) link = link_to_project(p, {:only_path => only_path}, :class => 'project') end end end end leading + (link || "#{project_prefix}#{prefix}#{sep}#{identifier}") end end HEADING_RE = /\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) # Renders the TOC with given headings def replace_toc(text, headings) text.gsub!(TOC_RE) do if headings.empty? '' else div_class = 'toc' div_class << ' right' if $1 == '>' div_class << ' left' if $1 == '<' out = "