Revision 1297:0a574315af3e .svn/pristine/3f
| .svn/pristine/3f/3f96fdb167ef6475d848f64ee14b65e8b759b8e8.svn-base | ||
|---|---|---|
| 1 |
# Redmine - project management software |
|
| 2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
class Watcher < ActiveRecord::Base |
|
| 19 |
belongs_to :watchable, :polymorphic => true |
|
| 20 |
belongs_to :user |
|
| 21 |
|
|
| 22 |
validates_presence_of :user |
|
| 23 |
validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id] |
|
| 24 |
validate :validate_user |
|
| 25 |
|
|
| 26 |
# Unwatch things that users are no longer allowed to view |
|
| 27 |
def self.prune(options={})
|
|
| 28 |
if options.has_key?(:user) |
|
| 29 |
prune_single_user(options[:user], options) |
|
| 30 |
else |
|
| 31 |
pruned = 0 |
|
| 32 |
User.find(:all, :conditions => "id IN (SELECT DISTINCT user_id FROM #{table_name})").each do |user|
|
|
| 33 |
pruned += prune_single_user(user, options) |
|
| 34 |
end |
|
| 35 |
pruned |
|
| 36 |
end |
|
| 37 |
end |
|
| 38 |
|
|
| 39 |
protected |
|
| 40 |
|
|
| 41 |
def validate_user |
|
| 42 |
errors.add :user_id, :invalid unless user.nil? || user.active? |
|
| 43 |
end |
|
| 44 |
|
|
| 45 |
private |
|
| 46 |
|
|
| 47 |
def self.prune_single_user(user, options={})
|
|
| 48 |
return unless user.is_a?(User) |
|
| 49 |
pruned = 0 |
|
| 50 |
find(:all, :conditions => {:user_id => user.id}).each do |watcher|
|
|
| 51 |
next if watcher.watchable.nil? |
|
| 52 |
|
|
| 53 |
if options.has_key?(:project) |
|
| 54 |
next unless watcher.watchable.respond_to?(:project) && watcher.watchable.project == options[:project] |
|
| 55 |
end |
|
| 56 |
|
|
| 57 |
if watcher.watchable.respond_to?(:visible?) |
|
| 58 |
unless watcher.watchable.visible?(user) |
|
| 59 |
watcher.destroy |
|
| 60 |
pruned += 1 |
|
| 61 |
end |
|
| 62 |
end |
|
| 63 |
end |
|
| 64 |
pruned |
|
| 65 |
end |
|
| 66 |
end |
|
| .svn/pristine/3f/3fc44a4cc04ed1435106069e4fc48b4490b1b6a0.svn-base | ||
|---|---|---|
| 1 |
<%= form_tag({:action => 'edit', :tab => 'repositories'}) do %>
|
|
| 2 |
|
|
| 3 |
<fieldset class="box settings enabled_scm"> |
|
| 4 |
<legend><%= l(:setting_enabled_scm) %></legend> |
|
| 5 |
<%= hidden_field_tag 'settings[enabled_scm][]', '' %> |
|
| 6 |
<table> |
|
| 7 |
<tr> |
|
| 8 |
<th></th> |
|
| 9 |
<th><%= l(:text_scm_command) %></th> |
|
| 10 |
<th><%= l(:text_scm_command_version) %></th> |
|
| 11 |
</tr> |
|
| 12 |
<% Redmine::Scm::Base.all.collect do |choice| %> |
|
| 13 |
<% scm_class = "Repository::#{choice}".constantize %>
|
|
| 14 |
<% text, value = (choice.is_a?(Array) ? choice : [choice, choice]) %> |
|
| 15 |
<% setting = :enabled_scm %> |
|
| 16 |
<% enabled = Setting.send(setting).include?(value) %> |
|
| 17 |
<tr> |
|
| 18 |
<td class="scm_name"> |
|
| 19 |
<label> |
|
| 20 |
<%= check_box_tag("settings[#{setting}][]", value, enabled, :id => nil) %>
|
|
| 21 |
<%= text.to_s %> |
|
| 22 |
</label> |
|
| 23 |
</td> |
|
| 24 |
<td> |
|
| 25 |
<% if enabled %> |
|
| 26 |
<%= |
|
| 27 |
image_tag( |
|
| 28 |
(scm_class.scm_available ? 'true.png' : 'exclamation.png'), |
|
| 29 |
:style => "vertical-align:bottom;" |
|
| 30 |
) |
|
| 31 |
%> |
|
| 32 |
<%= scm_class.scm_command %> |
|
| 33 |
<% end %> |
|
| 34 |
</td> |
|
| 35 |
<td> |
|
| 36 |
<%= scm_class.scm_version_string if enabled %> |
|
| 37 |
</td> |
|
| 38 |
</tr> |
|
| 39 |
<% end %> |
|
| 40 |
</table> |
|
| 41 |
<p><em class="info"><%= l(:text_scm_config) %></em></p> |
|
| 42 |
</fieldset> |
|
| 43 |
|
|
| 44 |
<div class="box tabular settings"> |
|
| 45 |
<p><%= setting_check_box :autofetch_changesets %></p> |
|
| 46 |
|
|
| 47 |
<p><%= setting_check_box :sys_api_enabled, |
|
| 48 |
:onclick => |
|
| 49 |
"if (this.checked) { $('#settings_sys_api_key').removeAttr('disabled'); } else { $('#settings_sys_api_key').attr('disabled', true); }" %></p>
|
|
| 50 |
|
|
| 51 |
<p><%= setting_text_field :sys_api_key, |
|
| 52 |
:size => 30, |
|
| 53 |
:id => 'settings_sys_api_key', |
|
| 54 |
:disabled => !Setting.sys_api_enabled?, |
|
| 55 |
:label => :setting_mail_handler_api_key %> |
|
| 56 |
<%= link_to_function l(:label_generate_key), |
|
| 57 |
"if (!$('#settings_sys_api_key').attr('disabled')) { $('#settings_sys_api_key').val(randomKey(20)) }" %>
|
|
| 58 |
</p> |
|
| 59 |
|
|
| 60 |
<p><%= setting_text_field :repository_log_display_limit, :size => 6 %></p> |
|
| 61 |
</div> |
|
| 62 |
|
|
| 63 |
<fieldset class="box tabular settings"> |
|
| 64 |
<legend><%= l(:text_issues_ref_in_commit_messages) %></legend> |
|
| 65 |
<p><%= setting_text_field :commit_ref_keywords, :size => 30 %> |
|
| 66 |
<em class="info"><%= l(:text_comma_separated) %></em></p> |
|
| 67 |
|
|
| 68 |
<p><%= setting_text_field :commit_fix_keywords, :size => 30 %> |
|
| 69 |
<%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id, |
|
| 70 |
[["", 0]] + |
|
| 71 |
IssueStatus.find(:all).collect{
|
|
| 72 |
|status| [status.name, status.id.to_s] |
|
| 73 |
}, |
|
| 74 |
:label => false %> |
|
| 75 |
<%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio, |
|
| 76 |
(0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] },
|
|
| 77 |
:blank => :label_no_change_option, |
|
| 78 |
:label => false %> |
|
| 79 |
<em class="info"><%= l(:text_comma_separated) %></em></p> |
|
| 80 |
|
|
| 81 |
<p><%= setting_check_box :commit_cross_project_ref %></p> |
|
| 82 |
|
|
| 83 |
<p><%= setting_check_box :commit_logtime_enabled, |
|
| 84 |
:onclick => |
|
| 85 |
"if (this.checked) { $('#settings_commit_logtime_activity_id').removeAttr('disabled'); } else { $('#settings_commit_logtime_activity_id').attr('disabled', true); }"%></p>
|
|
| 86 |
|
|
| 87 |
<p><%= setting_select :commit_logtime_activity_id, |
|
| 88 |
[[l(:label_default), 0]] + |
|
| 89 |
TimeEntryActivity.shared.active.collect{|activity| [activity.name, activity.id.to_s]},
|
|
| 90 |
:disabled => !Setting.commit_logtime_enabled?%></p> |
|
| 91 |
</fieldset> |
|
| 92 |
|
|
| 93 |
<%= submit_tag l(:button_save) %> |
|
| 94 |
<% end %> |
|
| .svn/pristine/3f/3feb470624b1737721fc273bdc7bfd57c3f458eb.svn-base | ||
|---|---|---|
| 1 |
# Redmine - project management software |
|
| 2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
require File.expand_path('../../../../test_helper', __FILE__)
|
|
| 19 |
|
|
| 20 |
class Redmine::CipheringTest < ActiveSupport::TestCase |
|
| 21 |
|
|
| 22 |
def test_password_should_be_encrypted |
|
| 23 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 24 |
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn') |
|
| 25 |
assert_equal 'foo', r.password |
|
| 26 |
assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) |
|
| 27 |
end |
|
| 28 |
end |
|
| 29 |
|
|
| 30 |
def test_password_should_be_clear_with_blank_key |
|
| 31 |
Redmine::Configuration.with 'database_cipher_key' => '' do |
|
| 32 |
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn') |
|
| 33 |
assert_equal 'foo', r.password |
|
| 34 |
assert_equal 'foo', r.read_attribute(:password) |
|
| 35 |
end |
|
| 36 |
end |
|
| 37 |
|
|
| 38 |
def test_password_should_be_clear_with_nil_key |
|
| 39 |
Redmine::Configuration.with 'database_cipher_key' => nil do |
|
| 40 |
r = Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'svn') |
|
| 41 |
assert_equal 'foo', r.password |
|
| 42 |
assert_equal 'foo', r.read_attribute(:password) |
|
| 43 |
end |
|
| 44 |
end |
|
| 45 |
|
|
| 46 |
def test_blank_password_should_be_clear |
|
| 47 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 48 |
r = Repository::Subversion.create!(:password => '', :url => 'file:///tmp', :identifier => 'svn') |
|
| 49 |
assert_equal '', r.password |
|
| 50 |
assert_equal '', r.read_attribute(:password) |
|
| 51 |
end |
|
| 52 |
end |
|
| 53 |
|
|
| 54 |
def test_unciphered_password_should_be_readable |
|
| 55 |
Redmine::Configuration.with 'database_cipher_key' => nil do |
|
| 56 |
r = Repository::Subversion.create!(:password => 'clear', :url => 'file:///tmp', :identifier => 'svn') |
|
| 57 |
end |
|
| 58 |
|
|
| 59 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 60 |
r = Repository.first(:order => 'id DESC') |
|
| 61 |
assert_equal 'clear', r.password |
|
| 62 |
end |
|
| 63 |
end |
|
| 64 |
|
|
| 65 |
def test_ciphered_password_with_no_cipher_key_configured_should_be_returned_ciphered |
|
| 66 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 67 |
r = Repository::Subversion.create!(:password => 'clear', :url => 'file:///tmp', :identifier => 'svn') |
|
| 68 |
end |
|
| 69 |
|
|
| 70 |
Redmine::Configuration.with 'database_cipher_key' => '' do |
|
| 71 |
r = Repository.first(:order => 'id DESC') |
|
| 72 |
# password can not be deciphered |
|
| 73 |
assert_nothing_raised do |
|
| 74 |
assert r.password.match(/\Aaes-256-cbc:.+\Z/) |
|
| 75 |
end |
|
| 76 |
end |
|
| 77 |
end |
|
| 78 |
|
|
| 79 |
def test_encrypt_all |
|
| 80 |
Repository.delete_all |
|
| 81 |
Redmine::Configuration.with 'database_cipher_key' => nil do |
|
| 82 |
Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'foo') |
|
| 83 |
Repository::Subversion.create!(:password => 'bar', :url => 'file:///tmp', :identifier => 'bar') |
|
| 84 |
end |
|
| 85 |
|
|
| 86 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 87 |
assert Repository.encrypt_all(:password) |
|
| 88 |
r = Repository.first(:order => 'id DESC') |
|
| 89 |
assert_equal 'bar', r.password |
|
| 90 |
assert r.read_attribute(:password).match(/\Aaes-256-cbc:.+\Z/) |
|
| 91 |
end |
|
| 92 |
end |
|
| 93 |
|
|
| 94 |
def test_decrypt_all |
|
| 95 |
Repository.delete_all |
|
| 96 |
Redmine::Configuration.with 'database_cipher_key' => 'secret' do |
|
| 97 |
Repository::Subversion.create!(:password => 'foo', :url => 'file:///tmp', :identifier => 'foo') |
|
| 98 |
Repository::Subversion.create!(:password => 'bar', :url => 'file:///tmp', :identifier => 'bar') |
|
| 99 |
|
|
| 100 |
assert Repository.decrypt_all(:password) |
|
| 101 |
r = Repository.first(:order => 'id DESC') |
|
| 102 |
assert_equal 'bar', r.password |
|
| 103 |
assert_equal 'bar', r.read_attribute(:password) |
|
| 104 |
end |
|
| 105 |
end |
|
| 106 |
end |
|
| .svn/pristine/3f/3fecfd23ccdcab419a5392dfa395ed433f4bc031.svn-base | ||
|---|---|---|
| 1 |
# Redmine - project management software |
|
| 2 |
# Copyright (C) 2006-2012 Jean-Philippe Lang |
|
| 3 |
# |
|
| 4 |
# This program is free software; you can redistribute it and/or |
|
| 5 |
# modify it under the terms of the GNU General Public License |
|
| 6 |
# as published by the Free Software Foundation; either version 2 |
|
| 7 |
# of the License, or (at your option) any later version. |
|
| 8 |
# |
|
| 9 |
# This program is distributed in the hope that it will be useful, |
|
| 10 |
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
| 11 |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
| 12 |
# GNU General Public License for more details. |
|
| 13 |
# |
|
| 14 |
# You should have received a copy of the GNU General Public License |
|
| 15 |
# along with this program; if not, write to the Free Software |
|
| 16 |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
| 17 |
|
|
| 18 |
module Redmine |
|
| 19 |
module Acts |
|
| 20 |
module Searchable |
|
| 21 |
def self.included(base) |
|
| 22 |
base.extend ClassMethods |
|
| 23 |
end |
|
| 24 |
|
|
| 25 |
module ClassMethods |
|
| 26 |
# Options: |
|
| 27 |
# * :columns - a column or an array of columns to search |
|
| 28 |
# * :project_key - project foreign key (default to project_id) |
|
| 29 |
# * :date_column - name of the datetime column (default to created_on) |
|
| 30 |
# * :sort_order - name of the column used to sort results (default to :date_column or created_on) |
|
| 31 |
# * :permission - permission required to search the model (default to :view_"objects") |
|
| 32 |
def acts_as_searchable(options = {})
|
|
| 33 |
return if self.included_modules.include?(Redmine::Acts::Searchable::InstanceMethods) |
|
| 34 |
|
|
| 35 |
cattr_accessor :searchable_options |
|
| 36 |
self.searchable_options = options |
|
| 37 |
|
|
| 38 |
if searchable_options[:columns].nil? |
|
| 39 |
raise 'No searchable column defined.' |
|
| 40 |
elsif !searchable_options[:columns].is_a?(Array) |
|
| 41 |
searchable_options[:columns] = [] << searchable_options[:columns] |
|
| 42 |
end |
|
| 43 |
|
|
| 44 |
searchable_options[:project_key] ||= "#{table_name}.project_id"
|
|
| 45 |
searchable_options[:date_column] ||= "#{table_name}.created_on"
|
|
| 46 |
searchable_options[:order_column] ||= searchable_options[:date_column] |
|
| 47 |
|
|
| 48 |
# Should we search custom fields on this model ? |
|
| 49 |
searchable_options[:search_custom_fields] = !reflect_on_association(:custom_values).nil? |
|
| 50 |
|
|
| 51 |
send :include, Redmine::Acts::Searchable::InstanceMethods |
|
| 52 |
end |
|
| 53 |
end |
|
| 54 |
|
|
| 55 |
module InstanceMethods |
|
| 56 |
def self.included(base) |
|
| 57 |
base.extend ClassMethods |
|
| 58 |
end |
|
| 59 |
|
|
| 60 |
module ClassMethods |
|
| 61 |
# Searches the model for the given tokens |
|
| 62 |
# projects argument can be either nil (will search all projects), a project or an array of projects |
|
| 63 |
# Returns the results and the results count |
|
| 64 |
def search(tokens, projects=nil, options={})
|
|
| 65 |
if projects.is_a?(Array) && projects.empty? |
|
| 66 |
# no results |
|
| 67 |
return [[], 0] |
|
| 68 |
end |
|
| 69 |
|
|
| 70 |
# TODO: make user an argument |
|
| 71 |
user = User.current |
|
| 72 |
tokens = [] << tokens unless tokens.is_a?(Array) |
|
| 73 |
projects = [] << projects unless projects.nil? || projects.is_a?(Array) |
|
| 74 |
|
|
| 75 |
find_options = {:include => searchable_options[:include]}
|
|
| 76 |
find_options[:order] = "#{searchable_options[:order_column]} " + (options[:before] ? 'DESC' : 'ASC')
|
|
| 77 |
|
|
| 78 |
limit_options = {}
|
|
| 79 |
limit_options[:limit] = options[:limit] if options[:limit] |
|
| 80 |
if options[:offset] |
|
| 81 |
limit_options[:conditions] = "(#{searchable_options[:date_column]} " + (options[:before] ? '<' : '>') + "'#{connection.quoted_date(options[:offset])}')"
|
|
| 82 |
end |
|
| 83 |
|
|
| 84 |
columns = searchable_options[:columns] |
|
| 85 |
columns = columns[0..0] if options[:titles_only] |
|
| 86 |
|
|
| 87 |
token_clauses = columns.collect {|column| "(LOWER(#{column}) LIKE ?)"}
|
|
| 88 |
|
|
| 89 |
if !options[:titles_only] && searchable_options[:search_custom_fields] |
|
| 90 |
searchable_custom_field_ids = CustomField.find(:all, |
|
| 91 |
:select => 'id', |
|
| 92 |
:conditions => { :type => "#{self.name}CustomField",
|
|
| 93 |
:searchable => true }).collect(&:id) |
|
| 94 |
if searchable_custom_field_ids.any? |
|
| 95 |
custom_field_sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
|
|
| 96 |
" WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
|
|
| 97 |
" AND #{CustomValue.table_name}.custom_field_id IN (#{searchable_custom_field_ids.join(',')}))"
|
|
| 98 |
token_clauses << custom_field_sql |
|
| 99 |
end |
|
| 100 |
end |
|
| 101 |
|
|
| 102 |
sql = (['(' + token_clauses.join(' OR ') + ')'] * tokens.size).join(options[:all_words] ? ' AND ' : ' OR ')
|
|
| 103 |
|
|
| 104 |
find_options[:conditions] = [sql, * (tokens.collect {|w| "%#{w.downcase}%"} * token_clauses.size).sort]
|
|
| 105 |
|
|
| 106 |
scope = self |
|
| 107 |
project_conditions = [] |
|
| 108 |
if searchable_options.has_key?(:permission) |
|
| 109 |
project_conditions << Project.allowed_to_condition(user, searchable_options[:permission] || :view_project) |
|
| 110 |
elsif respond_to?(:visible) |
|
| 111 |
scope = scope.visible(user) |
|
| 112 |
else |
|
| 113 |
ActiveSupport::Deprecation.warn "acts_as_searchable with implicit :permission option is deprecated. Add a visible scope to the #{self.name} model or use explicit :permission option."
|
|
| 114 |
project_conditions << Project.allowed_to_condition(user, "view_#{self.name.underscore.pluralize}".to_sym)
|
|
| 115 |
end |
|
| 116 |
# TODO: use visible scope options instead |
|
| 117 |
project_conditions << "#{searchable_options[:project_key]} IN (#{projects.collect(&:id).join(',')})" unless projects.nil?
|
|
| 118 |
project_conditions = project_conditions.empty? ? nil : project_conditions.join(' AND ')
|
|
| 119 |
|
|
| 120 |
results = [] |
|
| 121 |
results_count = 0 |
|
| 122 |
|
|
| 123 |
scope = scope.scoped({:conditions => project_conditions}).scoped(find_options)
|
|
| 124 |
results_count = scope.count(:all) |
|
| 125 |
results = scope.find(:all, limit_options) |
|
| 126 |
|
|
| 127 |
[results, results_count] |
|
| 128 |
end |
|
| 129 |
end |
|
| 130 |
end |
|
| 131 |
end |
|
| 132 |
end |
|
| 133 |
end |
|
Also available in: Unified diff